Токенная аутентификация DRF
Токены обеспечивают безопасный доступ к API без передачи логина и пароля. Это стандартный способ аутентификации для мобильных приложений и SPA.
Настройка токенов в settings.py
Создание токенов
Есть несколько способов создать токены для пользователей:
1. Автоматическое создание при регистрации
1from django.contrib.auth.models import User
2from rest_framework.authtoken.models import Token
3
4def create_user_with_token(username, email, password):
5 user = User.objects.create_user(username=username, email=email, password=password)
6 token, created = Token.objects.get_or_create(user=user)
7 return user, token
2. Создание через Django shell
3. Создание через management command
1# management/commands/create_tokens.py
2from django.core.management.base import BaseCommand
3from django.contrib.auth.models import User
4from rest_framework.authtoken.models import Token
5
6class Command(BaseCommand):
7 help = 'Create tokens for all users'
8
9 def handle(self, *args, **options):
10 for user in User.objects.all():
11 token, created = Token.objects.get_or_create(user=user)
12 if created:
13 self.stdout.write(f"Created token for {user.username}")
14 else:
15 self.stdout.write(f"Token already exists for {user.username}")
Защита API endpoints
Используй декораторы и миксины для защиты views:
Защита Class-Based Views
1from rest_framework import generics
2from rest_framework.permissions import IsAuthenticated
3from rest_framework.authentication import TokenAuthentication
4
5class UserProfileView(generics.RetrieveUpdateAPIView):
6 authentication_classes = [TokenAuthentication]
7 permission_classes = [IsAuthenticated]
8 serializer_class = UserSerializer
9
10 def get_object(self):
11 return self.request.user
Защита Function-Based Views
1from rest_framework.decorators import api_view, permission_classes, authentication_classes
2from rest_framework.permissions import IsAuthenticated
3from rest_framework.authentication import TokenAuthentication
4from rest_framework.response import Response
5
6@api_view(['GET'])
7@authentication_classes([TokenAuthentication])
8@permission_classes([IsAuthenticated])
9def protected_view(request):
10 return Response({
11 'message': f'Привет, {request.user.username}!',
12 'user_id': request.user.id
13 })
Использование токенов в запросах
Токен передается в заголовке Authorization:
Пример с curl
Пример с Python requests
Пример с JavaScript fetch
Создание API для получения токенов
Создай endpoint для аутентификации пользователей:
1# views.py
2from rest_framework import status
3from rest_framework.decorators import api_view, permission_classes
4from rest_framework.permissions import AllowAny
5from rest_framework.response import Response
6from rest_framework.authtoken.models import Token
7from django.contrib.auth import authenticate
8from django.views.decorators.csrf import csrf_exempt
9
10@api_view(['POST'])
11@permission_classes([AllowAny])
12@csrf_exempt
13def login_view(request):
14 username = request.data.get('username')
15 password = request.data.get('password')
16
17 if username and password:
18 user = authenticate(username=username, password=password)
19 if user:
20 token, created = Token.objects.get_or_create(user=user)
21 return Response({
22 'token': token.key,
23 'user_id': user.id,
24 'username': user.username
25 })
26 else:
27 return Response({
28 'error': 'Неверные учетные данные'
29 }, status=status.HTTP_400_BAD_REQUEST)
30 else:
31 return Response({
32 'error': 'Укажите username и password'
33 }, status=status.HTTP_400_BAD_REQUEST)
URLs для токенной аутентификации
Безопасность токенов
Важные моменты для безопасности:
1. Срок действия токенов
2. Удаление токенов при выходе
3. Проверка токенов в middleware
1# middleware.py
2from django.utils.deprecation import MiddlewareMixin
3from rest_framework.authtoken.models import Token
4
5class TokenValidationMiddleware(MiddlewareMixin):
6 def process_request(self, request):
7 auth_header = request.META.get('HTTP_AUTHORIZATION', '')
8 if auth_header.startswith('Token '):
9 token_key = auth_header.split(' ')[1]
10 try:
11 token = Token.objects.get(key=token_key)
12 request.user = token.user
13 except Token.DoesNotExist:
14 request.user = None
Тестирование токенной аутентификации
1# tests.py
2 from django.test import TestCase
3 from django.contrib.auth.models import User
4 from rest_framework.test import APIClient
5 from rest_framework.authtoken.models import Token
6
7 class TokenAuthenticationTest(TestCase):
8 def setUp(self):
9 self.client = APIClient()
10 self.user = User.objects.create_user(
11 username='testuser',
12 password='testpass123'
13 )
14 self.token = Token.objects.create(user=self.user)
15
16 def test_protected_endpoint_with_token(self):
17 self.client.credentials(HTTP_AUTHORIZATION=f'Token {self.token.key}')
18 response = self.client.get('/api/profile/')
19 self.assertEqual(response.status_code, 200)
20
21 def test_protected_endpoint_without_token(self):
22 response = self.client.get('/api/profile/')
23 self.assertEqual(response.status_code, 401)
FAQ
Q: Как генерировать токены для пользователей?
A: Используй Token.objects.get_or_create(user=user) или создавай через админку. Можно автоматизировать через signals или management commands.
Q: Как долго действуют токены?
A: По умолчанию токены не имеют срока действия. Рекомендуется настроить автоматическое удаление старых токенов или использовать JWT токены.
Q: Можно ли использовать несколько токенов для одного пользователя?
A: По умолчанию DRF создает только один токен на пользователя. Для множественных токенов используй кастомную модель или JWT.
Q: Как безопасно передавать токены в frontend?
A: Храни токены в localStorage или sessionStorage, используй HTTPS, и реализуй механизм обновления токенов.
Q: Что делать если токен скомпрометирован?
A: Немедленно удали токен через Token.objects.filter(user=user).delete() и создай новый. Рассмотри использование JWT с коротким сроком действия.
Q: Как добавить дополнительную информацию в токен?
A: Расширь модель Token или используй связанные модели для хранения дополнительных данных пользователя.