# 🔑 Authentication mit Django REST Framework (DRF)
## Inhaltsverzeichnis
1. [Einleitung](#einleitung)
2. [Grundlagen](#grundlagen)
3. [Schritt-für-Schritt-Aufbau](#schritt-für-schritt-aufbau)
- [1. App erstellen & DRF Paket installieren sowie settings anpassen](#1-app-erstellen--drf-paket-installieren-sowie-settings-anpassen)
- [2. Migrationen ausführen](#2-migrationen-ausführen)
- [3. Manuelle Token-Erzeugung im Admin](#3-manuelle-token-erzeugung-im-admin)
- [4. Testen mit Postman](#4-testen-mit-postman)
4. [Automatische Registrierung und Login Möglichkeiten](#automatische-registrierung-und-login-möglichkeiten)
- [1. Registration-Serializer mit Passwort-Bestätigung](#1-registration-serializer-mit-passwort-bestätigung)
- [2. Schneller Login-Endpoint mit `obtain_auth_token`](#2-schneller-login-endpoint-mit-obtain_auth_token)
- [3. CustomLoginView für erweiterte Antworten](#3-customloginview-für-erweiterte-antworten)
- [4. Optional: Automatische Token-Erzeugung via Signal bei Erstellung eines Users](#4-optional-automatische-token-erzeugung-via-signal-bei-erstellung-eines-users)
- [5. Logout View](#5-logout-view)
5. [Best Practices](#best-practices)
## Einleitung
Die Token-basierte Authentifizierung ist eine Methode, bei der Benutzer nach erfolgreicher Anmeldung ein einmaliges Token erhalten, das sie für alle nachfolgenden API-Anfragen im HTTP-Header `Authorization` mitsenden können. Sie ermöglicht eine zustandslose, skalierbare und sichere Kommunikation zwischen Client und Server, besonders geeignet für mobile und Single-Page-Applications.
## Grundlagen
### DRF-Paket und Modelle
Django REST Framework stellt mit `rest_framework.authtoken` das `Token`-Modell bereit, das von der Authentifizierungsklasse `TokenAuthentication` genutzt wird.
> Doku: https://www.django-rest-framework.org/api-guide/authentication/
---
## Schritt-für-Schritt-Aufbau
### 1. App erstellen & DRF Paket installieren sowie settings anpassen
```python
# settings.py
INSTALLED_APPS = [
...,
'rest_framework',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
```
### 2. Migrationen ausführen
Dies erzeugt die Tabelle `authtoken_token` für die Speicherung der Tokens.
### 3. Manuelle Token-Erzeugung im Admin
Im Django-Admin findest Du unter **Auth Token > Tokens** die Möglichkeit, für jeden User manuell ein Token anzulegen.
>Mit der Token-Authentifizierung bekommt jeder Benutzer einen eindeutigen Token. Anstatt bei jeder Anfrage seine Login-Daten (Benutzername und Passwort) zu senden, wird immer der Token verwendet und mitgeschickt, um den Benutzer zu authentifizieren und zu autorisieren. Dies erhöht die Sicherheit und vereinfacht die Authentifizierung, da der Benutzer nur den Token übermitteln muss, um Zugriff auf die geschützten Ressourcen zu erhalten.
### 4. Testen mit Postman
- Öffne Postman, setze bei **Headers** den Key `Authorization` mit dem Wert
```
Token <dein-token>
```
- Sende eine API-Anfrage an geschützte Endpunkte (Permission: isAuthenticated). Nur mit gültigem Token erhältst Du Zugriff.
## Automatische Registrierung und Login möglichkeiten
### 1. Registration-Serializer mit Passwort-Bestätigung
```python
# user_auth_app/serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
class RegistrationSerializer(serializers.ModelSerializer):
repeated_password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'repeated_password']
extra_kwargs = {
'password': {
'write_only': True
}
}
def save(self):
pw = self.validated_data['password']
repeated_pw = self.validated_data['repeated_password']
user_email = self.validated_data['email']
if pw != repeated_pw:
raise serializers.ValidationError({'error': 'Passwords do not match!'})
if User.objects.filter(email=user_email).exists():
raise serializers.ValidationError({'error': 'Email already exists!'})
if User.objects.filter(username=self.validated_data['username']).exists():
raise serializers.ValidationError({'error': 'Username already exists!'})
account = User(email=self.validated_data['email'], username=self.validated_data['username'])
account.set_password(pw)
account.save()
return account
```
### 2. Schneller Login-Endpoint mit `obtain_auth_token`
```python
# user_auth_app/urls.py
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('login/', obtain_auth_token, name='login'),
]
```
Hier sendet der User `username` und `password` und erhält bei Erfolg sein Token zurück.
>Doku: https://www.django-rest-framework.org/api-guide/authentication/#by-exposing-an-api-endpoint
### 3. CustomLoginView für erweiterte Antworten
```python
# user_auth_app/views.py
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
class CustomLoginView(ObtainAuthToken):
permission_classes = [AllowAny]
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'username': user.username,
'email': user.email,
})
```
Und in `urls.py`:
```python
path('login/', CustomLoginView.as_view(), name='custom-login')
```
So erhältst Du zusätzlich Benutzername und E-Mail im Response
>Doku: https://www.django-rest-framework.org/api-guide/authentication/#by-exposing-an-api-endpoint
>
---
### 4. Optional: Automatische Token-Erzeugung via Signal bei erstellung eines Users
```python
# user_auth_app/signals.py
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
```
Und verknüpfst die Datei in `apps.py` oder `__init__.py` Deiner App.
>Doku: https://www.django-rest-framework.org/api-guide/authentication/#by-using-signals
### 5. Logout View
```python
class LogoutView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request):
# Löscht das Token des aktuell authentifizierten Benutzers
request.user.auth_token.delete()
return Response(status=200)
```
---
## Best Practices
- **HTTPS**: Verwende in Produktion immer HTTPS, damit Tokens nicht abgefangen werden können.