Token, JWT, Session, OAuth2 — механизмы аутентификации в DRF
Аутентификация определяет, кто делает запрос. DRF предоставляет несколько встроенных схем аутентификации и позволяет создавать кастомные.
Аутентификация — процесс проверки личности пользователя. В DRF аутентификация происходит до проверки прав доступа (permissions) и троттлинга.
Глобальная настройка в settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}Порядок важен: DRF пробует классы по порядку. Первый успешный метод аутентифицирует пользователя.
Использует сессионную аутентификацию Django:
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
"""SessionAuthentication без CSRF для API"""
def enforce_csrf(self, request):
return # Не проверять CSRF для APIОсобенности:
Использование:
# views.py
from rest_framework.views import APIView
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
class ProtectedView(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({'user': request.user.username})Аутентификация по токену:
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework.authtoken', # Обязательно для TokenAuthentication
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}Создание токена для пользователя:
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
user = User.objects.get(username='john')
token = Token.objects.create(user=user)
print(token.key) # Строковый ключ токенаИспользование токена в запросе:
curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" \
http://example.com/api/protected/View для получения токена:
# views.py
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomObtainAuthToken(ObtainAuthToken):
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, 'user_id': user.pk})
# urls.py
urlpatterns = [
path('api-token-auth/', CustomObtainAuthToken.as_view()),
]# 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)Аутентификация через заголовок Authorization с кодировкой Base64:
from rest_framework.authentication import BasicAuthentication
class BasicAuthView(APIView):
authentication_classes = [BasicAuthentication]
permission_classes = [IsAuthenticated]Запрос:
curl -u username:password http://example.com/api/protected/
# Или вручную:
# Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=Не рекомендуется для production без HTTPS, так как пароль передаётся в каждом запросе.
JWT (JSON Web Token) — современный стандарт аутентификации. Реализуется через djangorestframework-simplejwt:
pip install djangorestframework-simplejwt# settings.py
INSTALLED_APPS = [
# ...
'rest_framework_simplejwt',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
}URL для получения токенов:
# urls.py
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
path('api/token/', TokenObtainPairView.as_view()),
path('api/token/refresh/', TokenRefreshView.as_view()),
path('api/token/verify/', TokenVerifyView.as_view()),
]Получение токенов:
# POST /api/token/
{
"username": "john",
"password": "secret123"
}
# Ответ:
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}Использование access токена:
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
http://example.com/api/protected/Обновление токена:
# POST /api/token/refresh/
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
# Ответ:
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}Создание своего класса аутентификации:
from rest_framework import authentication
from rest_framework import exceptions
from django.contrib.auth.models import User
class CustomHeaderAuthentication(authentication.BaseAuthentication):
"""Аутентификация по кастомному заголовку X-API-Key"""
def authenticate(self, request):
api_key = request.META.get('HTTP_X_API_KEY')
if not api_key:
return None # Нет ключа — не наша аутентификация
try:
user = User.objects.get(api_key=api_key)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid API key')
return (user, None) # (user, auth_details)
def authenticate_header(self, request):
return 'X-API-Key' # Для WWW-Authenticate заголовкаМожно переопределить классы аутентификации для конкретного view:
from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class ProtectedView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({'user': request.user.username})
# Или отключить аутентификацию для конкретного view
class PublicView(APIView):
authentication_classes = [] # Нет аутентификации
permission_classes = [] # Нет проверок прав
def get(self, request):
return Response({'message': 'Public data'})from rest_framework import viewsets
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
serializer.save(author=self.request.user)| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
| Session | Встроен в Django, удобно для браузера | CSRF, не для мобильных | Веб-приложения внутри домена |
| Token | Простота, stateless | Токен не истекает, нужно хранить | Простые API, мобильные приложения |
| JWT | Stateless, есть refresh, масштабируемость | Сложнее, токены больше | Микросервисы, SPA, мобильные |
| Basic | Простота | Пароль в каждом запросе | Только для тестов/dev |
| Custom | Полный контроль | Нужно реализовывать | Специфичные требования |
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.