You've already forked public-gists
286 lines
8.9 KiB
Markdown
286 lines
8.9 KiB
Markdown
|
|
Конечно! Ниже приведён перевод предыдущего ответа на русский язык.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### ✅ Как реализовать JWT в проекте Django с помощью `djangorestframework-simplejwt` (без `python-jose`)
|
|||
|
|
|
|||
|
|
Чтобы реализовать **JWT (JSON Web Tokens)** в проекте Django с использованием пакета **`djangorestframework-simplejwt`** (без `python-jose`), следуйте пошаговой инструкции ниже. Этот пакет лёгкий, хорошо поддерживается и отлично интегрируется с Django REST Framework.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 📌 Предварительные требования
|
|||
|
|
|
|||
|
|
Убедитесь, что у вас установлено:
|
|||
|
|
- Django
|
|||
|
|
- Django REST Framework (`djangorestframework`)
|
|||
|
|
- Python 3.6 или выше
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 1. Установите необходимые пакеты
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install djangorestframework
|
|||
|
|
pip install djangorestframework-simplejwt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> ✅ Примечание: `simplejwt` **не требует** `python-jose` или `cryptography` для базового алгоритма HMAC (HS256). Он использует встроенный механизм подписи Django или стандартные модули Python `hmac` и `hashlib`. Модуль `cryptography` нужен только при использовании RSA (RS256).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. Обновите `settings.py`
|
|||
|
|
|
|||
|
|
Добавьте `rest_framework` и настройте `SimpleJWT`:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# settings.py
|
|||
|
|
|
|||
|
|
INSTALLED_APPS = [
|
|||
|
|
'django.contrib.admin',
|
|||
|
|
'django.contrib.auth',
|
|||
|
|
'django.contrib.contenttypes',
|
|||
|
|
'django.contrib.sessions',
|
|||
|
|
'django.contrib.messages',
|
|||
|
|
'django.contrib.staticfiles',
|
|||
|
|
|
|||
|
|
# Сторонние приложения
|
|||
|
|
'rest_framework',
|
|||
|
|
|
|||
|
|
# Ваши приложения
|
|||
|
|
'myapp',
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
# Настройки REST Framework
|
|||
|
|
REST_FRAMEWORK = {
|
|||
|
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
|||
|
|
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
|||
|
|
),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Настройки SimpleJWT (необязательно)
|
|||
|
|
from datetime import timedelta
|
|||
|
|
|
|||
|
|
SIMPLE_JWT = {
|
|||
|
|
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
|
|||
|
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
|||
|
|
'ROTATE_REFRESH_TOKENS': False,
|
|||
|
|
'BLACKLIST_AFTER_ROTATION': True,
|
|||
|
|
'UPDATE_LAST_LOGIN': False,
|
|||
|
|
|
|||
|
|
'ALGORITHM': 'HS256',
|
|||
|
|
'SIGNING_KEY': SECRET_KEY, # Использует SECRET_KEY из Django
|
|||
|
|
'VERIFYING_KEY': None,
|
|||
|
|
'AUDIENCE': None,
|
|||
|
|
'ISSUER': None,
|
|||
|
|
'JSON_ENCODER': None,
|
|||
|
|
'JWK_URL': None,
|
|||
|
|
'LEEWAY': 0,
|
|||
|
|
|
|||
|
|
'AUTH_HEADER_TYPES': ('Bearer',),
|
|||
|
|
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
|||
|
|
'USER_ID_FIELD': 'id',
|
|||
|
|
'USER_ID_CLAIM': 'user_id',
|
|||
|
|
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
|
|||
|
|
|
|||
|
|
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
|
|||
|
|
'TOKEN_TYPE_CLAIM': 'token_type',
|
|||
|
|
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
|
|||
|
|
|
|||
|
|
'JTI_CLAIM': 'jti',
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 🔐 `SIGNING_KEY` по умолчанию берётся из `SECRET_KEY`, если не указан явно. HS256 использует симметричное шифрование — один и тот же ключ для подписи и проверки.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. Настройте URL-адреса
|
|||
|
|
|
|||
|
|
Добавьте в основной `urls.py` эндпоинты для получения и обновления токенов:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# urls.py (уровень проекта)
|
|||
|
|
from django.contrib import admin
|
|||
|
|
from django.urls import path, include
|
|||
|
|
from rest_framework_simplejwt.views import (
|
|||
|
|
TokenObtainPairView,
|
|||
|
|
TokenRefreshView,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
urlpatterns = [
|
|||
|
|
path('admin/', admin.site.urls),
|
|||
|
|
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|||
|
|
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|||
|
|
path('api/', include('myapp.urls')),
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. Защитите свои API-эндпоинты
|
|||
|
|
|
|||
|
|
Используйте декораторы или классы для защиты представлений.
|
|||
|
|
|
|||
|
|
Пример с функцией:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# views.py в вашем приложении
|
|||
|
|
from rest_framework.decorators import api_view, permission_classes, authentication_classes
|
|||
|
|
from rest_framework.response import Response
|
|||
|
|
from rest_framework.permissions import IsAuthenticated
|
|||
|
|
from rest_framework.authentication import SessionAuthentication
|
|||
|
|
|
|||
|
|
@api_view(['GET'])
|
|||
|
|
@permission_classes([IsAuthenticated])
|
|||
|
|
@authentication_classes([SessionAuthentication]) # Опционально: отключите сессию, если используете только JWT
|
|||
|
|
def protected_view(request):
|
|||
|
|
return Response({
|
|||
|
|
'message': 'Привет! Вы прошли аутентификацию!',
|
|||
|
|
'user': request.user.username
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Или с классом:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from rest_framework.views import APIView
|
|||
|
|
from rest_framework.response import Response
|
|||
|
|
from rest_framework.permissions import IsAuthenticated
|
|||
|
|
|
|||
|
|
class ProtectedView(APIView):
|
|||
|
|
permission_classes = [IsAuthenticated]
|
|||
|
|
|
|||
|
|
def get(self, request):
|
|||
|
|
return Response({
|
|||
|
|
'message': f'Привет, {request.user.username}, вы авторизованы через JWT!'
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Добавьте маршрут в `myapp/urls.py`:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# myapp/urls.py
|
|||
|
|
from django.urls import path
|
|||
|
|
from .views import ProtectedView
|
|||
|
|
|
|||
|
|
urlpatterns = [
|
|||
|
|
path('protected/', ProtectedView.as_view(), name='protected'),
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 5. Проверка работы JWT
|
|||
|
|
|
|||
|
|
#### Шаг 1: Получение токенов
|
|||
|
|
|
|||
|
|
Отправьте POST-запрос на `/api/token/` с данными пользователя:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
POST /api/token/
|
|||
|
|
Content-Type: application/json
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"username": "ваш_логин",
|
|||
|
|
"password": "ваш_пароль"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
✅ Ответ:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"refresh": "eyJ...",
|
|||
|
|
"access": "eyJ..."
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Шаг 2: Доступ к защищённому эндпоинту
|
|||
|
|
|
|||
|
|
Используйте токен доступа в заголовке:
|
|||
|
|
|
|||
|
|
```http
|
|||
|
|
GET /api/protected/
|
|||
|
|
Authorization: Bearer eyJ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Шаг 3: Обновление токена доступа
|
|||
|
|
|
|||
|
|
Когда токен доступа истекает:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
POST /api/token/refresh/
|
|||
|
|
Content-Type: application/json
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"refresh": "eyJ..."
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
✅ Вернётся новый `access` токен.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 6. Дополнительно: Добавление пользовательских данных в токен
|
|||
|
|
|
|||
|
|
Вы можете добавить свои поля в токен, переопределив `TokenObtainPairSerializer`.
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# serializers.py
|
|||
|
|
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
|||
|
|
from rest_framework_simplejwt.views import TokenObtainPairView
|
|||
|
|
|
|||
|
|
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
|
|||
|
|
@classmethod
|
|||
|
|
def get_token(cls, user):
|
|||
|
|
token = super().get_token(user)
|
|||
|
|
|
|||
|
|
# Добавляем свои поля
|
|||
|
|
token['username'] = user.username
|
|||
|
|
token['email'] = user.email
|
|||
|
|
token['is_staff'] = user.is_staff
|
|||
|
|
|
|||
|
|
return token
|
|||
|
|
|
|||
|
|
# views.py
|
|||
|
|
class MyTokenObtainPairView(TokenObtainPairView):
|
|||
|
|
serializer_class = MyTokenObtainPairSerializer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Обновите URL:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# urls.py
|
|||
|
|
path('api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Теперь в токене будут дополнительные данные!
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### ✅ Итог
|
|||
|
|
|
|||
|
|
Вы успешно реализовали JWT в Django с помощью `djangorestframework-simplejwt` без использования `python-jose`. Основные моменты:
|
|||
|
|
|
|||
|
|
- Используется встроенная криптография Django (`hmac` + `sha256`) для HS256
|
|||
|
|
- Не нужны `python-jose`, `cryptography` и другие внешние зависимости
|
|||
|
|
- Простая интеграция с DRF
|
|||
|
|
- Поддержка access/refresh токенов «из коробки»
|
|||
|
|
- Возможность настройки содержимого токена
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🛡️ Рекомендации по безопасности
|
|||
|
|
|
|||
|
|
- Храните `SECRET_KEY` в безопасности и никогда не показывайте его.
|
|||
|
|
- Используйте HTTPS в продакшене.
|
|||
|
|
- Включите чёрный список токенов, если пользователи могут выходить из системы.
|
|||
|
|
- Установите разумное время жизни токенов.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
Сообщите, если хотите:
|
|||
|
|
- Реализовать регистрацию пользователей
|
|||
|
|
- Настроить чёрный список токенов
|
|||
|
|
- Использовать RS256 (асимметричное шифрование)
|
|||
|
|
- Добавить выход из системы (с блокировкой токена)
|
|||
|
|
- Интеграцию с фронтендом (React, Vue и т.д.)
|