В современном мире веб-разработки аутентификация пользователей играет критически важную роль. Django REST Framework (DRF) предоставляет мощные инструменты для создания RESTful API, а интеграция аутентификации на основе электронной почты и JWT (JSON Web Tokens) обеспечивает безопасный и масштабируемый способ управления доступом к ресурсам. В этой статье мы рассмотрим, как настроить аутентификацию и вход пользователей в DRF с использованием электронной почты в качестве логина и JWT для защиты API.
Настройка окружения и необходимые зависимости
Прежде чем приступить к реализации, необходимо настроить окружение и установить необходимые пакеты.
Установка Django REST Framework и необходимых пакетов
Начнем с установки Django, DRF и библиотеки для работы с JWT:
pip install django djangorestframework djangorestframework-simplejwt
-
django— основной фреймворк. -
djangorestframework— для создания REST API. -
djangorestframework-simplejwt— для работы с JWT.
Настройка проекта Django: создание приложения ‘users’ и моделей
Создадим новое приложение Django под названием users:
python manage.py startapp users
Добавьте rest_framework и users в INSTALLED_APPS в файле settings.py:
INSTALLED_APPS = [
...
'rest_framework',
'users',
]
Реализация модели пользователя и сериализаторов
Создание кастомной модели User с использованием email в качестве username
В файле users/models.py создадим кастомную модель пользователя, где email будет использоваться в качестве username:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Email must be provided')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(email, password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, verbose_name='email address')
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
Укажите эту модель в AUTH_USER_MODEL в settings.py:
AUTH_USER_MODEL = 'users.User'
Выполните миграции:
python manage.py makemigrations
python manage.py migrate
Создание сериализаторов для регистрации и входа пользователей
Создадим сериализаторы в users/serializers.py для регистрации и входа пользователей:
from rest_framework import serializers
from .models import User
from django.contrib.auth import authenticate
class RegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
password2 = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'password', 'password2')
extra_kwargs = {
'first_name': {'required': True},
'last_name': {'required': True}
}
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError("Passwords do not match.")
return data
def create(self, validated_data):
validated_data.pop('password2')
password = validated_data.pop('password')
user = User.objects.create_user(email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'])
user.set_password(password)
user.save()
return user
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
password = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
def validate(self, data):
email = data.get('email', None)
password = data.get('password', None)
if email and password:
user = authenticate(email=email, password=password)
if user:
if user.is_active:
data['user'] = user
else:
raise serializers.ValidationError("User is not active.")
else:
raise serializers.ValidationError("Unable to login with provided credentials.")
else:
raise serializers.ValidationError("Must include 'email' and 'password'.")
return data
Реализация логики аутентификации и работы с JWT
Создание представлений (views) для регистрации и входа
Создадим представления для регистрации и входа пользователей в users/views.py:
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from .serializers import RegistrationSerializer, LoginSerializer
class RegistrationAPIView(generics.GenericAPIView):
serializer_class = RegistrationSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=True):
user = serializer.validated_data['user']
refresh = RefreshToken.for_user(user)
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
}, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Настройка аутентификации на основе JWT: генерация токенов и защита API
Добавим URL-пути в users/urls.py:
from django.urls import path
from .views import RegistrationAPIView, LoginAPIView
urlpatterns = [
path('register/', RegistrationAPIView.as_view(), name='register'),
path('login/', LoginAPIView.as_view(), name='login'),
]
Включим эти URL-пути в основной urls.py файл проекта:
from django.urls import path, include
urlpatterns = [
path('api/users/', include('users.urls')),
]
Настроим DRF для использования JWT аутентификации в settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
Безопасность, обработка ошибок и дополнительные улучшения
Рекомендации по безопасности: хэширование паролей, валидация данных
-
Хэширование паролей: Django автоматически хэширует пароли при создании пользователя, используя надежные алгоритмы. Убедитесь, что используете последние версии Django для актуальных алгоритмов.
-
Валидация данных: Валидируйте все входящие данные на сервере, чтобы предотвратить SQL-инъекции и другие уязвимости. DRF предоставляет мощные инструменты для валидации данных в сериализаторах.
-
HTTPS: Используйте HTTPS для шифрования трафика между клиентом и сервером, защищая данные аутентификации от перехвата.
-
CORS: Настройте CORS (Cross-Origin Resource Sharing) для контроля доступа к API только с доверенных доменов.
Обработка ошибок и предоставление понятных сообщений пользователям
-
Обработка исключений: Перехватывайте исключения и возвращайте понятные сообщения об ошибках пользователям. Используйте middleware для глобальной обработки исключений.
-
Валидация на стороне клиента: Добавьте валидацию на стороне клиента для улучшения пользовательского опыта и снижения нагрузки на сервер.
-
Логирование: Включите логирование для отслеживания ошибок и подозрительной активности.
Заключение
В этой статье мы рассмотрели, как настроить аутентификацию и вход пользователей в Django REST Framework с использованием электронной почты в качестве логина и JWT для защиты API. Следуя этим шагам, вы сможете создать безопасный и масштабируемый API для вашего веб-приложения. Не забывайте о важности безопасности и валидации данных, чтобы защитить ваше приложение от уязвимостей. 🚀