Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Miron-Anosov/07164f264eec2a353ffd43dacc5668f5 to your computer and use it in GitHub Desktop.
Save Miron-Anosov/07164f264eec2a353ffd43dacc5668f5 to your computer and use it in GitHub Desktop.

Django Authentication & Authorization Guide

Содержание

  1. Введение в аутентификацию и авторизацию
  2. Система пользователей Django
  3. Аутентификация
  4. Авторизация
  5. Декораторы и миксины
  6. Группы и разрешения
  7. Лучшие практики

Введение

Аутентификация и авторизация - два фундаментальных аспекта безопасности веб-приложений:

  • Аутентификация - процесс проверки подлинности пользователя (кто этот пользователь?)
  • Авторизация - процесс проверки прав доступа (что пользователю разрешено делать?)

Django предоставляет комплексную систему для работы с обоими аспектами.

Система пользователей Django

Django использует встроенную модель пользователя django.contrib.auth.models.User, которая включает базовые поля:

  • username
  • password
  • email
  • 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 предоставляет несколько инструментов для контроля доступа:

  1. login_required - базовая проверка аутентификации:
from django.contrib.auth.decorators import login_required

@login_required
def protected_view(request):
    """
    Представление, доступное только аутентифицированным пользователям
    """
    return HttpResponse("Секретные данные")
  1. 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("Данные модели")
  1. 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')
        )

Лучшие практики

  1. Использование декораторов и миксинов:

    • Применяйте декораторы для функциональных представлений
    • Используйте миксины для классов представлений
    • Комбинируйте проверки при необходимости
  2. Работа с группами:

    • Создавайте группы для общих наборов разрешений
    • Используйте сигналы для автоматического назначения групп
    • Регулярно аудируйте разрешения групп
  3. Безопасность:

    • Всегда используйте HTTPS
    • Применяйте принцип наименьших привилегий
    • Регулярно проверяйте и обновляйте разрешения
  4. Проверки доступа:

# 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)
  1. Кастомная аутентификация:
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
  1. Управление сессиями:
# settings.py
SESSION_COOKIE_AGE = 3600  # 1 час
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_SECURE = True  # Только HTTPS
  1. Логирование действий:
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)
  1. Тестирование безопасности:
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 в области безопасности.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment