Чувак, тема с JWT и Django REST Framework (DRF) сначала кажется жесткой, но когда врубаешься — всё становится на места. Сам через это прошел, лови выжимку личного опыта без воды:
Зачем Simple-JWT?
- Это надстройка над DRF для аутентификации через JWT-токены (как те ключи-карты в фитнесе, только для API).
- JWT — это не куки: токен хранится у клиента (например, в localStorage браузера) и при каждом запросе летит в заголовке.
- Проще сессий: не нужно хранить состояние на сервере. Особенно кайфово для мобилок и SPA (типа твоего React-фронта).
Как вьехать (по шагам):
1. Ставим пакеты:
bash
Copy
pip install djangorestframework-simplejwt
2. В settings.py добавляем настройки:
python
Copy
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication', # ключевая строка
),
}
# Настройки срока жизни токенов (можно кастомить)
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), # доступ короткий
'REFRESH_TOKEN_LIFETIME': timedelta(days=7), # обновление долгое
}
3. В urls.py проекта добавляем эндпоинты для работы с токенами:
python
Copy
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # получаем токен по логину/паролю
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # обновляем access-токен
]
Как это работает на практике:
- Фронт шлет логин/пароль на /api/token/ → в ответе получает:
json
Copy
{
"refresh": "aaaaa.bbbbb.ccccc",
"access": "xxxxx.yyyyy.zzzzz"
}
- access — токен для доступа к защищенным API (живет недолго).
- refresh — токен для обновления access (живет долго).
- При каждом запросе к бэку фронт добавляет в заголовок:
http
Copy
Authorization: Bearer xxxxx.yyyyy.zzzzz
- Когда access протух → фронт шлет refresh на /api/token/refresh/ → получает новый access.
Лайфхаки:
- Кастомизация токенов (добавить данные юзера в токен):
Создай файл serializers.py в своем приложении:
python
Copy
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username # добавляем свои поля
token['is_admin'] = user.is_staff
return token
# В urls.py подмени вьюху:
from .serializers import MyTokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
# И используй эту вьюху в урлах вместо стандартной.
- Защита эндпоинтов:
На любом DRF-вьюхе (или ViewSet) добавь пермишены:
python
Copy
from rest_framework.permissions import IsAuthenticated
class SecretDataView(APIView):
permission_classes = [IsAuthenticated] # только для авторизованных
- Тестирование через Postman:
- Шли POST на /api/token/ с username и password в body → получи токен.
- Далее делай запросы к защищенным урлам, добавляя заголовок Authorization: Bearer <access_token>.
Где чаще всего ловлю косяки:
- CORS — если фронт на другом порту, Django будет блокировать запросы. Решение:
- Поставь django-cors-headers → настрой CORS_ALLOWED_ORIGINS в settings.py.
- Не обновляется access-токен — фронт должен отслеживать 401 ошибку и автоматически шлять refresh.
- Токен не попадает в заголовок — проверь, что фронт правильно его вставляет (лучше через axios-интерцепторы или fetch).
Пример с фронтом (React):
javascript
Copy
// Логин
const login = async (username, password) => {
const response = await fetch('/api/token/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const data = await response.json();
localStorage.setItem('access_token', data.access);
localStorage.setItem('refresh_token', data.refresh);
};
// Запрос к защищенному API
const fetchData = async () => {
const token = localStorage.getItem('access_token');
const response = await fetch('/api/secret/', {
headers: {
'Authorization':
Bearer ${token}
,
},
});
if (response.status === 401) {
// Токен умер, пробуем обновить через refresh
// ... тут код для refresh
}
return response.json();
};
Полезные ссылки:
P.S. Если уперся в конкретную ошибку — пиши, разберемся. Первые пару дней чувствуешь себя обезьяной с гранатой, потом привыкаешь