🐛 Типичные ошибки: Auth/DRF
⚡ Топ-5 ошибок
- Не добавить
rest_framework.authtokenвINSTALLED_APPSи/или не сделатьmigrate - Написать
TokenвместоBearerв заголовке JWT (или наоборот) - Настроить auth глобально в settings.py, но не переопределить для конкретных представлений
- Не установить
djangorestframework-simplejwtперед настройкой JWTAuthentication - Не добавить маршруты получения токена (
obtain_auth_token/TokenObtainPairView) вurls.py
Ошибка 1: Забыли migrate для TokenAuthentication
Симптом:
ProgrammingError: relation "authtoken_token" does not exist
Неверно
INSTALLED_APPS = [
'rest_framework.authtoken',
]
# Забыли выполнить:
# python manage.py migrate
Верно
INSTALLED_APPS = [
'rest_framework.authtoken',
]
# Обязательно выполнить:
# python manage.py migrate
# Проверить: таблица authtoken_token создана
Почему: rest_framework.authtoken добавляет Django-модель Token. Как и любая другая модель, она требует миграции для создания таблицы в БД.
Ошибка 2: Неправильный формат заголовка Authorization
Симптом: HTTP 401 при правильном токене
Неверно
# Для TokenAuthentication
Authorization: Bearer 9944b0... # НЕВЕРНО!
Authorization: Basic 9944b0... # НЕВЕРНО!
# Для JWTAuthentication
Authorization: Token eyJhbGci... # НЕВЕРНО!
Authorization: Basic eyJhbGci... # НЕВЕРНО!
Верно
# Для TokenAuthentication
Authorization: Token 9944b0... # ВЕРНО
# Для JWTAuthentication
Authorization: Bearer eyJhbGci... # ВЕРНО
# Для BasicAuthentication
Authorization: Basic dXNlcm5... # ВЕРНО
Почему: Каждый механизм аутентификации ожидает своё ключевое слово в заголовке. DRF проверяет именно это слово, чтобы понять, какой класс должен обрабатывать запрос.
Ошибка 3: Конфликт глобальных и поуровневых настроек
Симптом: Аутентификация работает не так, как ожидалось
Путаница
# settings.py — глобально JWT
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
# views.py — но забыли переопределить для публичных
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
# Нет permission_classes -> используется глобальный IsAuthenticated
# Доступ закрыт для анонимов, хотя хотели открытый!
Верно
# views.py — явно задаём для публичных представлений
from rest_framework.permissions import AllowAny
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
permission_classes = [AllowAny] # Явно открытый
# Или задаём глобальный AllowAny и закрываем только нужные
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}
Ошибка 4: Пакет не установлен
Симптом:
ModuleNotFoundError: No module named 'rest_framework_simplejwt'
# Неверно: сразу добавить в settings.py без установки
INSTALLED_APPS = ['rest_framework_simplejwt'] # ModuleNotFoundError!
# Верно: сначала установить
pip install djangorestframework-simplejwt
# Затем добавить в settings.py
Ошибка 5: Нет маршрута для получения токена
Симптом:
404 Not Found при попытке получить токен
# Неверно: настроили TokenAuthentication, но нет маршрута
# пользователь пытается POST /api-token-auth/ -> 404
# Верно: явно добавить маршрут в urls.py
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('api-token-auth/', obtain_auth_token, name='api_token_auth'),
]
Почему: DRF не добавляет маршруты автоматически. obtain_auth_token — это обычное представление, которое нужно явно зарегистрировать в urlpatterns.
Ошибка 6: access-токен JWT истёк, не используют refresh
Симптом: HTTP 401
{"detail": "Given token not valid for any token type", "code": "token_not_valid"} через 5 минут после получения токена
# Неверно: пытаться использовать истёкший access-токен
# Верно: обновить access-токен через refresh
# POST http://127.0.0.1:8000/api/token/refresh/
# Body: {"refresh": "eyJhbGci...refresh_token..."}
# Ответ: {"access": "eyJhbGci...новый_access..."}
# Убедиться, что маршрут зарегистрирован:
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh')
Ошибка 7: BasicAuthentication без HTTPS в production
Симптом: Утечка учётных данных пользователей
# Проблема: Base64 — не шифрование
import base64
base64.b64decode("dXNlcm5hbWU6cGFzc3dvcmQ=")
# => b'username:password' — тривиально раскодируется!
# Правило: BasicAuthentication только с HTTPS в production
# Для development/тестирования — допустимо
# Для production — только поверх TLS/SSL