🐛 Типичные ошибки — Урок 40
⚡ Топ-5 ошибок при настройке аутентификации
- Забыть добавить
rest_framework.authtokenв INSTALLED_APPS →OperationalError: no such table - Не выполнить
python manage.py migrateпосле добавления authtoken → та же ошибка - Использовать
TokenвместоBearerв заголовке JWT → 401 Unauthorized User.objects.create(password='...')вместоcreate_user()→ пароль в открытом виде- BasicAuthentication без HTTPS в production → перехват учётных данных
Ошибка 1: Забытый rest_framework.authtoken в INSTALLED_APPS
Симптом
django.db.utils.OperationalError: no such table: authtoken_token
Причина
TokenAuthentication требует отдельного приложения rest_framework.authtoken, которое добавляет модель Token и таблицу в БД.
Неправильно
INSTALLED_APPS = [
'rest_framework',
# rest_framework.authtoken ЗАБЫТО
'myapp',
]
Правильно
INSTALLED_APPS = [
'rest_framework',
'rest_framework.authtoken', # ← обязательно
'myapp',
]
# И затем:
# python manage.py migrate
Ошибка 2: Неправильный формат заголовка Authorization
Симптом
HTTP 401 Unauthorized
{"detail": "Authentication credentials were not provided."}
Причина
Путаница между схемами Token (DRF) и Bearer (JWT).
Неправильно
# При использовании TokenAuthentication:
Authorization: Bearer abc123def456
# При использовании JWTAuthentication:
Authorization: Token eyJhbGci...
Правильно
# TokenAuthentication:
Authorization: Token abc123def456
# JWTAuthentication (Simple JWT):
Authorization: Bearer eyJhbGci...
Ошибка 3: Создание пользователя с нехешированным паролем
Симптом
Пользователь создан, но не может войти — пароль хранится в открытом виде в БД.
Неправильно
from django.contrib.auth.models import User
# ← password сохраняется в открытом виде!
user = User.objects.create(
username='alice',
password='secret123'
)
Правильно
from django.contrib.auth.models import User
# create_user() хеширует пароль через PBKDF2
user = User.objects.create_user(
username='alice',
password='secret123',
email='alice@example.com'
)
Ошибка 4: Смешение глобальных и локальных настроек
Симптом
Неожиданное поведение разрешений — одни представления требуют аутентификации, другие нет, хотя должны.
Неправильно
# settings.py — разрешено всем
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny', # ← опасно!
],
}
# views.py — забыли переопределить
class SecretView(APIView):
# нет permission_classes — применится AllowAny
def get(self, request):
return Response({"secret": "data"})
Правильно
# settings.py — строго по умолчанию
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
# views.py — явно открываем публичные
class PublicView(APIView):
permission_classes = [AllowAny] # ← явное исключение
...
class SecretView(APIView):
# наследует IsAuthenticated из глобальных
def get(self, request):
return Response({"secret": "data"})
Принцип безопасности: всегда используйте максимально строгие настройки по умолчанию. Открывайте доступ явно, а не закрывайте по необходимости.
Ошибка 5: BasicAuthentication в production без HTTPS
Симптом
API работает, но учётные данные можно перехватить сниффером. Base64 — не шифрование!
# Base64 легко декодировать:
import base64
base64.b64decode('YWxpY2U6c2VjcmV0MTIz').decode()
# 'alice:secret123' ← учётные данные в открытом виде
⚠️ BasicAuthentication должен использоваться ТОЛЬКО с HTTPS. В production всегда применяйте TLS/SSL.
Ошибка 6: Неправильная конфигурация Simple JWT
Симптом
ImportError: cannot import name 'JWTAuthentication' from 'rest_framework'
Причина
Simple JWT — отдельная библиотека, импорт идёт не из rest_framework, а из rest_framework_simplejwt.
Неправильно
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# ← неверный модуль!
'rest_framework.authentication.JWTAuthentication',
],
}
Правильно
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# ← правильный модуль
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
Ошибка 7: Отправка access-токена вместо refresh при обновлении
Симптом
HTTP 401
{"detail": "Token is invalid or expired", "code": "token_not_valid"}
Причина
Эндпоинт /api/token/refresh/ ожидает refresh-токен, а не access-токен.
Неправильно
# POST /api/token/refresh/
{
"refresh": "eyJ... (access токен)" # ← ошибка!
}
Правильно
# POST /api/token/refresh/
{
"refresh": "eyJ... (refresh токен из /api/token/)"
}
# Ответ: {"access": "eyJ... (новый access токен)"}