- Введение в аутентификацию и авторизацию
- Система пользователей Django
- Аутентификация
- Авторизация
- Декораторы и миксины
- Группы и разрешения
- Лучшие практики
Аутентификация и авторизация - два фундаментальных аспекта безопасности веб-приложений:
- Аутентификация - процесс проверки подлинности пользователя (кто этот пользователь?)
- Авторизация - процесс проверки прав доступа (что пользователю разрешено делать?)
Django предоставляет комплексную систему для работы с обоими аспектами.
Django использует встроенную модель пользователя django.contrib.auth.models.User
, которая включает базовые поля:
- username
- password
- first_name
- last_name
- is_active
- is_staff
- is_superuser
- date_joined
- last_login
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
"""
Расширенная модель пользователя
Добавляет дополнительные поля к стандартной модели User
"""
phone = models.CharField(max_length=15, blank=True)
birth_date = models.DateField(null=True, blank=True)
class Meta:
permissions = [
("can_view_dashboard", "Может просматривать панель управления"),
("can_export_data", "Может экспортировать данные")
]
# views.py
from django.contrib.auth import authenticate, login
def login_view(request):
"""
Представление для аутентификации пользователя
Проверяет credentials и выполняет вход в систему
"""
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
return render(request, 'login.html', {'error': 'Неверные данные'})
return render(request, 'login.html')
# views.py
from django.contrib.auth.models import User, Group
class RegistrationView(CreateView):
"""
Представление для регистрации нового пользователя
Создает пользователя и назначает базовые разрешения
"""
model = User
form_class = UserCreationForm
template_name = 'registration.html'
def form_valid(self, form):
response = super().form_valid(form)
# Создаем профиль пользователя
Profile.objects.create(user=self.object)
# Добавляем пользователя в группу по умолчанию
default_group = Group.objects.get(name='basic_users')
self.object.groups.add(default_group)
# Автоматический вход после регистрации
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
user = authenticate(self.request, username=username, password=password)
login(self.request, user)
return response
Django предоставляет несколько инструментов для контроля доступа:
- login_required - базовая проверка аутентификации:
from django.contrib.auth.decorators import login_required
@login_required
def protected_view(request):
"""
Представление, доступное только аутентифицированным пользователям
"""
return HttpResponse("Секретные данные")
- permission_required - проверка конкретных разрешений:
from django.contrib.auth.decorators import permission_required
@permission_required('app.view_model', raise_exception=True)
def view_protected_model(request):
"""
Представление, требующее специального разрешения
raise_exception=True вызовет 403 вместо редиректа на страницу входа
"""
return HttpResponse("Данные модели")
- user_passes_test - кастомная проверка условий:
from django.contrib.auth.decorators import user_passes_test
def is_manager(user):
"""
Проверка является ли пользователь менеджером
"""
return user.groups.filter(name='Managers').exists()
@user_passes_test(is_manager)
def manager_view(request):
"""
Представление доступное только менеджерам
"""
return HttpResponse("Панель управления менеджера")
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
UserPassesTestMixin
)
class ProtectedView(LoginRequiredMixin, PermissionRequiredMixin, View):
"""
Представление с комбинацией проверок доступа
"""
permission_required = 'app.special_permission'
login_url = '/login/'
redirect_field_name = 'next'
def get(self, request):
return HttpResponse("Защищенный контент")
class SuperUserView(UserPassesTestMixin, View):
"""
Представление только для суперпользователей
"""
def test_func(self):
return self.request.user.is_superuser
# management/commands/setup_groups.py
from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import MyModel
class Command(BaseCommand):
"""
Команда для начальной настройки групп и разрешений
Использование: python manage.py setup_groups
"""
def handle(self, *args, **options):
# Создаем группу
editors_group, created = Group.objects.get_or_create(name='Editors')
# Получаем content type для модели
content_type = ContentType.objects.get_for_model(MyModel)
# Создаем разрешения
view_permission = Permission.objects.create(
codename='can_view_special',
name='Can view special content',
content_type=content_type,
)
edit_permission = Permission.objects.create(
codename='can_edit_special',
name='Can edit special content',
content_type=content_type,
)
# Назначаем разрешения группе
editors_group.permissions.add(view_permission, edit_permission)
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User, Group
@receiver(post_save, sender=User)
def assign_default_permissions(sender, instance, created, **kwargs):
"""
Сигнал для автоматического назначения разрешений новым пользователям
"""
if created:
# Добавляем пользователя в группу по умолчанию
default_group = Group.objects.get(name='BasicUsers')
instance.groups.add(default_group)
# Назначаем индивидуальные разрешения
instance.user_permissions.add(
Permission.objects.get(codename='can_view_public_content')
)
-
Использование декораторов и миксинов:
- Применяйте декораторы для функциональных представлений
- Используйте миксины для классов представлений
- Комбинируйте проверки при необходимости
-
Работа с группами:
- Создавайте группы для общих наборов разрешений
- Используйте сигналы для автоматического назначения групп
- Регулярно аудируйте разрешения групп
-
Безопасность:
- Всегда используйте HTTPS
- Применяйте принцип наименьших привилегий
- Регулярно проверяйте и обновляйте разрешения
-
Проверки доступа:
# views.py
class SecureView(View):
"""
Пример комплексной проверки доступа
"""
def dispatch(self, request, *args, **kwargs):
# Проверка аутентификации
if not request.user.is_authenticated:
return redirect('login')
# Проверка активности пользователя
if not request.user.is_active:
return HttpResponse('Аккаунт деактивирован', status=403)
# Проверка специальных разрешений
if not request.user.has_perm('app.special_permission'):
return HttpResponse('Нет доступа', status=403)
return super().dispatch(request, *args, **kwargs)
- Кастомная аутентификация:
from django.contrib.auth.backends import BaseBackend
class EmailAuthBackend(BaseBackend):
"""
Бэкенд для аутентификации по email вместо username
"""
def authenticate(self, request, email=None, password=None):
try:
user = User.objects.get(email=email)
if user.check_password(password):
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
- Управление сессиями:
# settings.py
SESSION_COOKIE_AGE = 3600 # 1 час
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_SECURE = True # Только HTTPS
- Логирование действий:
import logging
logger = logging.getLogger(__name__)
class AuditMiddleware:
"""
Middleware для аудита действий пользователей
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
logger.info(
'User %s accessed %s',
request.user.username,
request.path
)
return self.get_response(request)
- Тестирование безопасности:
from django.test import TestCase
from django.urls import reverse
class SecurityTests(TestCase):
"""
Тесты безопасности аутентификации и авторизации
"""
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
def test_login_required(self):
"""
Проверка что защищенные URL недоступны без аутентификации
"""
response = self.client.get(reverse('protected_view'))
self.assertEqual(response.status_code, 302) # Редирект на логин
self.client.login(username='testuser', password='testpass123')
response = self.client.get(reverse('protected_view'))
self.assertEqual(response.status_code, 200) # Доступ разрешен
Эта документация охватывает основные аспекты работы с аутентификацией и авторизацией в Django. При реализации системы безопасности важно регулярно обновлять знания о лучших практиках и следить за обновлениями Django в области безопасности.