Houd me bezig met het implementeren van een aangepast API-sleutelbeheersysteem in mijn Django-toepassing
description
Door het implementeren van een aangepast API-sleutelbeheersysteem, kunt u de beveiliging verbeteren, de toegang tot uw API's controleren en het gebruik effectief monitoren, zodat alleen geautoriseerde gebruikers toegang krijgen tot uw diensten.
prompt
try_prompt
Help me bij het ontwerpen en implementeren van een aangepast API-sleutelbeheersysteem in mijn Django-toepassing om toegang tot mijn API's te controleren. Beschrijf mijn huidige API-instelli ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht en advies over het ontwerpen en implementeren van een aangepast API-sleutelbeheersysteem in je Django-toepassing, rekening houdend met jouw huidige OAuth2-configuratie en specifieke functies.
**Huidige situatie:**
- Je gebruikt OAuth2 voor authenticatie.
- Je wilt aanvullende API-sleutelbeheerfunctionaliteiten toevoegen, zoals verval na 30 dagen, gebruikslimieten, en intrekkingsproces.
---
### 1. Integratie van API-sleutels naast OAuth2
Omdat OAuth2 al wordt gebruikt, kun je API-sleutels implementeren als een extra laag of alternatieve authenticatiemethode voor bepaalde API-endpoints.
**Aanbevelingen:**
- Voeg een model toe voor API-sleutels (`ApiKey`) dat gerelateerd is aan je gebruikers of applicaties.
- Sla gegevens op zoals:
- Sleutel (uniek token)
- Aanmaakdatum
- Vervaldatum (30 dagen na creatie)
- Gebruikslimieten (bijvoorbeeld max aantal verzoeken per dag)
- Status (actief, ingetrokken, verlopen)
### 2. Modeldefinitie voor API-sleutels
```python
from django.db import models
from django.contrib.auth.models import User
import uuid
from django.utils import timezone
from datetime import timedelta
class ApiKey(models.Model):
key = models.CharField(max_length=40, unique=True, default=uuid.uuid4().hex)
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField()
is_active = models.BooleanField(default=True)
request_limit = models.IntegerField(default=1000) # bijvoorbeeld
requests_made = models.IntegerField(default=0)
def save(self, *args, **kwargs):
if not self.expires_at:
self.expires_at = self.created_at + timedelta(days=30)
super().save(*args, **kwargs)
def is_expired(self):
return timezone.now() > self.expires_at
def revoke(self):
self.is_active = False
self.save()
```
### 3. Functionaliteiten voor beheer
- **Verval na 30 dagen:** Bij creatie wordt `expires_at` ingesteld op 30 dagen na aanmaak.
- **Gebruikslimieten:** Bij elke API-aanvraag wordt gecontroleerd of het verzoek het limiet overschrijdt.
- **Intrekkingsproces:** Een admin kan sleutels handmatig intrekken (`revoke()`).
### 4. Middleware of decorator voor verificatie
Maak een middleware of decorator die controleert:
- Of de API-sleutel geldig en actief is.
- Of deze niet is verlopen.
- Of het gebruikslimiet niet is overschreden.
Voorbeeld van verificatie:
```python
def check_api_key(request):
api_key = request.headers.get('X-API-KEY')
if not api_key:
return False
try:
key_obj = ApiKey.objects.get(key=api_key, is_active=True)
except ApiKey.DoesNotExist:
return False
if key_obj.is_expired() or not key_obj.is_active:
return False
if key_obj.requests_made >= key_obj.request_limit:
return False
# Verhoog verzoekaantal
key_obj.requests_made += 1
key_obj.save()
return True
```
### 5. Automatisering en beheer
- Plan een periodieke taak (bijv. via Celery of Django-cron) om verlopen sleutels te archiveren of te deactiveren.
- Creëer admin-interfaces voor het genereren, intrekken en bekijken van API-sleutels.
---
### Samenvattend:
- Voeg een `ApiKey`-model toe met vervaldatum en gebruikslimieten.
- Stel automatische verval in op 30 dagen.
- Controleer sleutels bij elke API-aanvraag.
- Bied beheermogelijkheden voor het intrekken en monitoren van sleutels.
Wil je dat ik je help met de volledige code-implementatie of integratie in je bestaande project?
provider: deepseek
model: deepseek-chat
Hier is een gedetailleerd plan voor het implementeren van een aangepast API-sleutelbeheersysteem in je Django-applicatie naast je bestaande OAuth2-authenticatie:
## 1. Datamodel Ontwerp
```python
# models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import secrets
import hashlib
class APIKey(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100, help_text="Beschrijvende naam voor deze sleutel")
# Sleutel opslag (hash voor veiligheid)
key_hash = models.CharField(max_length=64, unique=True)
prefix = models.CharField(max_length=8, unique=True)
# Vervalinstellingen
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField()
is_active = models.BooleanField(default=True)
# Gebruikslimieten
rate_limit = models.IntegerField(default=1000, help_text="Aanvragen per dag")
requests_today = models.IntegerField(default=0)
last_reset = models.DateField(auto_now_add=True)
class Meta:
db_table = 'api_keys'
class APIKeyUsage(models.Model):
api_key = models.ForeignKey(APIKey, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
endpoint = models.CharField(max_length=200)
ip_address = models.GenericIPAddressField()
class Meta:
db_table = 'api_key_usage'
```
## 2. Sleutel Generator en Beheer
```python
# utils/apikey_utils.py
import secrets
import hashlib
from datetime import timedelta
from django.utils import timezone
class APIKeyManager:
@staticmethod
def generate_key():
"""Genereer een nieuwe API-sleutel"""
raw_key = secrets.token_urlsafe(32)
prefix = raw_key[:8]
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
return {
'raw_key': raw_key,
'prefix': prefix,
'key_hash': key_hash
}
@staticmethod
def create_api_key(user, name, rate_limit=1000):
"""Creëer een nieuwe API-sleutel voor gebruiker"""
key_data = APIKeyManager.generate_key()
expires_at = timezone.now() + timedelta(days=30)
api_key = APIKey.objects.create(
user=user,
name=name,
prefix=key_data['prefix'],
key_hash=key_data['key_hash'],
expires_at=expires_at,
rate_limit=rate_limit
)
return key_data['raw_key'], api_key
@staticmethod
def validate_key(raw_key):
"""Valideer een API-sleutel"""
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
try:
api_key = APIKey.objects.get(
key_hash=key_hash,
is_active=True,
expires_at__gt=timezone.now()
)
# Reset dagelijkse telling indien nodig
if api_key.last_reset < timezone.now().date():
api_key.requests_today = 0
api_key.last_reset = timezone.now().date()
api_key.save()
# Controleer rate limit
if api_key.requests_today >= api_key.rate_limit:
return None
api_key.requests_today += 1
api_key.save()
return api_key
except APIKey.DoesNotExist:
return None
```
## 3. Authenticatie Middleware
```python
# middleware/apikey_middleware.py
from django.utils.deprecation import MiddlewareMixin
from .utils.apikey_utils import APIKeyManager
from .models import APIKeyUsage
class APIKeyMiddleware(MiddlewareMixin):
def process_request(self, request):
# Skip voor OAuth2 routes
if request.path.startswith('/o/'):
return None
# Zoek API-sleutel in headers
api_key = request.headers.get('X-API-Key')
if api_key:
validated_key = APIKeyManager.validate_key(api_key)
if validated_key:
request.api_key = validated_key
# Log gebruik
APIKeyUsage.objects.create(
api_key=validated_key,
endpoint=request.path,
ip_address=self.get_client_ip(request)
)
return None
else:
from django.http import JsonResponse
return JsonResponse(
{'error': 'Ongeldige of verlopen API-sleutel'},
status=401
)
return None
def get_client_ip(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
```
## 4. Beheer Views
```python
# views/apikey_views.py
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import APIKey
from .utils.apikey_utils import APIKeyManager
@login_required
def create_api_key(request):
if request.method == 'POST':
name = request.POST.get('name')
rate_limit = int(request.POST.get('rate_limit', 1000))
raw_key, api_key = APIKeyManager.create_api_key(
request.user, name, rate_limit
)
return JsonResponse({
'success': True,
'api_key': raw_key, # Toon alleen eenmalig!
'prefix': api_key.prefix,
'expires_at': api_key.expires_at.isoformat()
})
return JsonResponse({'error': 'Alleen POST toegestaan'}, status=405)
@login_required
def list_api_keys(request):
keys = APIKey.objects.filter(user=request.user).values(
'id', 'name', 'prefix', 'created_at',
'expires_at', 'is_active', 'rate_limit'
)
return JsonResponse({'api_keys': list(keys)})
@login_required
def revoke_api_key(request, key_id):
try:
api_key = APIKey.objects.get(id=key_id, user=request.user)
api_key.is_active = False
api_key.save()
return JsonResponse({'success': True})
except APIKey.DoesNotExist:
return JsonResponse({'error': 'Sleutel niet gevonden'}, status=404)
```
## 5. Scheduled Tasks voor Onderhoud
```python
# management/commands/cleanup_expired_keys.py
from django.core.management.base import BaseCommand
from django.utils import timezone
from api_keys.models import APIKey
class Command(BaseCommand):
help = 'Verwijder verlopen API-sleutels'
def handle(self, *args, **options):
expired_count = APIKey.objects.filter(
expires_at__lt=timezone.now()
).update(is_active=False)
self.stdout.write(
f'{expired_count} verlopen API-sleutels gedeactiveerd'
)
```
## 6. Configuratie
```python
# settings.py
MIDDLEWARE = [
# ... andere middleware
'yourapp.middleware.apikey_middleware.APIKeyMiddleware',
]
# Voeg toe aan INSTALLED_APPS
INSTALLED_APPS = [
# ... andere apps
'api_keys',
]
# Cron job voor dagelijkse cleanup (toevoegen aan crontab)
# 0 2 * * * /path/to/venv/python /path/to/manage.py cleanup_expired_keys
```
## 7. Gebruik in je API
```python
# views.py
from django.http import JsonResponse
def my_api_view(request):
if hasattr(request, 'api_key'):
# API-sleutel authenticatie
user = request.api_key.user
# Je bedrijfslogica hier
return JsonResponse({'data': 'API-sleutel toegang'})
else:
# OAuth2 authenticatie (bestaande logica)
return JsonResponse({'data': 'OAuth2 toegang'})
```
## Belangrijke Beveiligingsoverwegingen:
1. **Sleutels hashen** voor opslag
2. **Rate limiting** per sleutel
3. **Automatische vervaldatum** (30 dagen)
4. **Gebruikslogging** voor monitoring
5. **Prefix tonen** in beheerinterface (nooit volledige sleutel)
Dit systeem werkt naast je bestaande OAuth2 en biedt eenvoudige sleutelbeheer voor machine-to-machine communicatie.

