Аутентификация и авторизация в Django: полное руководство пользователя
Для кого эта статья:
- Профессиональные Django-разработчики
- Студенты и начинающие программисты, желающие углубить знания в Django
Разработчики, ищущие рекомендации по настройке аутентификации и авторизации в своих проектах
Первый пользовательский вопрос, с которым сталкивается каждый Django-разработчик: "Как управлять доступом к моему приложению?". Именно от грамотно настроенной аутентификации и авторизации зависит, насколько безопасным и удобным будет ваше веб-приложение. Но разница между этими понятиями, настройка кастомных моделей пользователей и реализация сложной логики разграничения прав часто становятся камнем преткновения даже для опытных программистов. Сегодня разбираемся с нуля, как правильно настроить всё это в Django — с рабочими примерами кода, который вы сможете адаптировать под свои задачи. 🔐
Если вы хотите освоить Django на профессиональном уровне и создавать безопасные веб-приложения, обратите внимание на Обучение Python-разработке от Skypro. Курс построен на практических задачах, включая детальное изучение систем аутентификации и авторизации, с которыми вы будете работать в реальных проектах. Преподаватели — действующие разработчики, которые покажут, как избежать типичных ошибок при работе с Django-аутентификацией и разграничением прав.
Что такое аутентификация и авторизация в Django
Прежде чем погрузиться в код, давайте чётко разграничим два ключевых понятия, которые часто путают между собой:
- Аутентификация — процесс проверки личности пользователя (кто вы?)
- Авторизация — процесс определения, что пользователю разрешено делать (что вам можно?)
Django предоставляет мощную встроенную систему для обоих процессов, которая реализуется через несколько компонентов:
| Компонент | Назначение | Ключевые функции |
|---|---|---|
| django.contrib.auth | Ядро системы аутентификации | Базовые модели User, Group; хеширование паролей |
| Authentication backends | Механизмы проверки учетных данных | ModelBackend (стандартный), другие бэкенды (LDAP, OAuth) |
| Permission system | Система разрешений | Проверка прав на уровне модели и объекта |
| Django Admin | Административный интерфейс | Управление пользователями и группами |
Максим Ковалёв, Senior Django-разработчик
Однажды мы разрабатывали платформу для врачей, где доступ к медицинским данным требовал особой защиты. Я решил использовать стандартную систему Django для быстрого запуска. Большая ошибка! Уже через месяц нам потребовалось добавить несколько уровней доступа для разных специалистов, а стандартная модель User не поддерживала нужную гибкость.
Пришлось переписывать всю логику, когда система уже работала с реальными данными. Теперь я всегда начинаю с планирования кастомной модели пользователя, даже если проект кажется простым. Поверьте, нет ничего сложнее, чем мигрировать пользовательские данные на новую модель в действующем приложении.
Для типичного веб-приложения процесс работы с пользователем выглядит так:
- Пользователь регистрируется (создается запись в таблице User)
- Система сохраняет пароль в хешированном виде (PBKDF2 + SHA256 по умолчанию)
- При последующих входах введенный пароль хешируется и сравнивается с сохраненным
- После успешного входа создается сессия, хранящая информацию о пользователе
- При доступе к защищенным ресурсам система проверяет права пользователя
Django использует модель User из пакета django.contrib.auth.models для хранения информации о пользователях. Эта модель включает базовые поля: username, email, password, firstname, lastname, isactive, isstaff и is_superuser. 🧩

Базовая настройка системы аутентификации Django
Включить систему аутентификации в Django просто. Если вы использовали команду startproject, то базовая конфигурация уже присутствует в settings.py.
Проверьте, что в INSTALLED_APPS есть необходимые приложения:
INSTALLED_APPS = [
# ...
'django.contrib.auth', # Система аутентификации
'django.contrib.contenttypes', # Необходима для работы auth
# ...
]
Убедитесь, что в MIDDLEWARE присутствуют необходимые компоненты:
MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware', # Для работы с сессиями
# ...
'django.contrib.auth.middleware.AuthenticationMiddleware', # Для аутентификации
# ...
]
Также важно настроить параметры аутентификации в settings.py:
# URL для перенаправления после успешного входа
LOGIN_REDIRECT_URL = 'home'
# URL для перенаправления, если доступ запрещен
LOGIN_URL = 'login'
# URL для перенаправления после выхода
LOGOUT_REDIRECT_URL = 'home'
# Бэкенды аутентификации
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
# Здесь можно добавить кастомные бэкенды
]
# Хешеры паролей (в порядке их применения)
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]
После настройки выполните миграции, чтобы создать необходимые таблицы в базе данных:
python manage.py migrate
Теперь вы можете создать суперпользователя для доступа к административной панели:
python manage.py createsuperuser
С базовой настройкой у вас уже есть возможность:
- Создавать и управлять пользователями через Django Admin
- Аутентифицировать пользователей с помощью form-based аутентификации
- Контролировать доступ к представлениям с помощью декораторов
- Проверять и управлять разрешениями пользователей
Однако для большинства реальных приложений этого недостаточно. Перейдем к созданию кастомной модели пользователя. 🔧
Создание кастомной модели пользователя
Стандартная модель User в Django хороша для быстрого старта, но для серьезных проектов вам почти наверняка потребуется кастомная модель. И важно спланировать это до начала разработки, поскольку изменить модель User после создания миграций крайне сложно.
Django предлагает несколько способов расширения стандартной модели User:
| Подход | Преимущества | Недостатки | Когда использовать |
|---|---|---|---|
| Proxy Model | Простота реализации, не требует миграций | Нельзя добавить новые поля | Для изменения поведения без изменения структуры |
| OneToOneField (Profile) | Сохраняет совместимость с auth.User | Требует дополнительных запросов к БД | Для добавления полей к существующему проекту |
| AbstractUser | Сохраняет функционал User с возможностью расширения | Жесткая привязка к username | Когда вас устраивает базовая структура auth.User |
| AbstractBaseUser | Полная свобода в определении структуры | Требует реализации многих методов вручную | Для полностью кастомной системы аутентификации |
Наиболее гибкий подход — наследование от AbstractBaseUser. Рассмотрим его реализацию:
Сначала создайте модель пользователя в вашем приложении (например, accounts/models.py):
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.utils import timezone
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Email is required')
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=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
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)
date_joined = models.DateTimeField(default=timezone.now)
# Дополнительные поля для вашего приложения
phone_number = models.CharField(max_length=15, blank=True)
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
objects = CustomUserManager()
USERNAME_FIELD = 'email' # Поле для аутентификации (вместо username)
REQUIRED_FIELDS = [] # Дополнительные обязательные поля
def __str__(self):
return self.email
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip() or self.email
def get_short_name(self):
return self.first_name or self.email
Затем укажите Django использовать вашу кастомную модель в settings.py:
AUTH_USER_MODEL = 'accounts.CustomUser'
Не забудьте создать и применить миграции:
python manage.py makemigrations
python manage.py migrate
Для работы с кастомной моделью в административной панели, создайте файл accounts/admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ('email', 'first_name', 'last_name', 'is_staff', 'is_active')
list_filter = ('is_staff', 'is_active')
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'phone_number', 'bio', 'avatar')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email', 'first_name', 'last_name')
ordering = ('email',)
admin.site.register(CustomUser, CustomUserAdmin)
Преимущество этого подхода заключается в том, что вы полностью контролируете модель пользователя и можете адаптировать её под требования вашего проекта. 👨💻
Анна Соколова, Python-разработчик
Я работала над платформой для онлайн-курсов, где требовалось разделять пользователей на студентов, преподавателей и администраторов. Поначалу использовали стандартную модель User и группы для разграничения ролей. Но когда потребовалось добавить специфичные для каждой роли поля (для студентов — прогресс обучения, для преподавателей — опыт и специализация), код стал запутанным.
Мы переписали систему с использованием AbstractBaseUser и добавили поле user_type с выбором типа пользователя. Затем создали отдельные модели Student, Teacher и Administrator, связанные с основной моделью через OneToOneField. Это позволило нам иметь единую систему аутентификации, но при этом гибко работать с различными типами пользователей.
Главный урок, который я извлекла: планируйте модель пользователя на этапе проектирования архитектуры. Лучше потратить день на создание кастомной модели, чем неделю на миграцию данных в производственной среде.
Регистрация и вход в приложении на Django
После настройки кастомной модели пользователя нам нужно реализовать регистрацию, вход и выход из системы. Django предоставляет несколько готовых классов представлений для этих задач, но часто требуется их кастомизация. 🔑
Начнем с создания форм в accounts/forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm
from django.contrib.auth import get_user_model
User = get_user_model()
class CustomUserCreationForm(UserCreationForm):
"""Форма для регистрации новых пользователей"""
email = forms.EmailField(
max_length=254,
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email'})
)
password1 = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Пароль'})
)
password2 = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Подтверждение пароля'})
)
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'password1', 'password2')
widgets = {
'first_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Имя'}),
'last_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Фамилия'}),
}
def clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Пользователь с таким email уже существует")
return email
class CustomAuthenticationForm(AuthenticationForm):
"""Форма для аутентификации пользователей"""
username = forms.EmailField(
max_length=254,
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email'})
)
password = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Пароль'})
)
Теперь создадим представления в accounts/views.py:
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.views import View
from django.utils.decorators import method_decorator
from django.urls import reverse_lazy
from django.contrib import messages
from django.views.generic import CreateView, TemplateView
from .forms import CustomUserCreationForm, CustomAuthenticationForm
class SignUpView(CreateView):
form_class = CustomUserCreationForm
template_name = 'accounts/signup.html'
success_url = reverse_lazy('login')
def form_valid(self, form):
response = super().form_valid(form)
messages.success(self.request, 'Регистрация успешна! Теперь вы можете войти.')
return response
class LoginView(View):
form_class = CustomAuthenticationForm
template_name = 'accounts/login.html'
def get(self, request):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(data=request.POST)
if form.is_valid():
email = form.cleaned_data.get('username') # В форме поле называется username
password = form.cleaned_data.get('password')
user = authenticate(username=email, password=password)
if user is not None:
login(request, user)
messages.success(request, f'Добро пожаловать, {user.get_short_name()}!')
return redirect('home')
return render(request, self.template_name, {'form': form})
def logout_view(request):
logout(request)
messages.success(request, 'Вы успешно вышли из системы.')
return redirect('home')
@method_decorator(login_required, name='dispatch')
class ProfileView(TemplateView):
template_name = 'accounts/profile.html'
Затем добавим URL-маршруты в accounts/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUpView.as_view(), name='signup'),
path('login/', views.LoginView.as_view(), name='login'),
path('logout/', views.logout_view, name='logout'),
path('profile/', views.ProfileView.as_view(), name='profile'),
]
Не забудьте включить их в главный urls.py проекта:
from django.urls import path, include
urlpatterns = [
# ...
path('accounts/', include('accounts.urls')),
# ...
]
Наконец, создадим шаблоны для наших представлений. Вот пример шаблона для регистрации (templates/accounts/signup.html):
{% extends 'base.html' %}
{% block content %}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">Регистрация</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
<div class="form-group mb-3">
{{ form.email.label_tag }}
{{ form.email }}
{% if form.email.errors %}
<div class="text-danger">{{ form.email.errors }}</div>
{% endif %}
</div>
<div class="form-group mb-3">
{{ form.first_name.label_tag }}
{{ form.first_name }}
</div>
<div class="form-group mb-3">
{{ form.last_name.label_tag }}
{{ form.last_name }}
</div>
<div class="form-group mb-3">
{{ form.password1.label_tag }}
{{ form.password1 }}
{% if form.password1.errors %}
<div class="text-danger">{{ form.password1.errors }}</div>
{% endif %}
<small class="form-text text-muted">{{ form.password1.help_text }}</small>
</div>
<div class="form-group mb-3">
{{ form.password2.label_tag }}
{{ form.password2 }}
{% if form.password2.errors %}
<div class="text-danger">{{ form.password2.errors }}</div>
{% endif %}
</div>
<button type="submit" class="btn btn-primary">Зарегистрироваться</button>
</form>
</div>
<div class="card-footer">
Уже есть аккаунт? <a href="{% url 'login' %}">Войти</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Для аутентификации через социальные сети можно использовать библиотеку python-social-auth или django-allauth. Они предоставляют готовые решения для интеграции OAuth с популярными сервисами. 🌐
Разграничение прав доступа с декораторами и миксинами
После настройки аутентификации необходимо реализовать авторизацию — то есть определить, что каждый пользователь может делать в вашем приложении. Django предлагает несколько уровней контроля доступа:
- Проверка аутентификации (пользователь вошел в систему)
- Проверка разрешений на уровне модели (пользователь имеет определенное право)
- Проверка разрешений на уровне объекта (пользователь может работать с конкретным объектом)
- Кастомные проверки (любая произвольная логика)
Рассмотрим основные инструменты для реализации авторизации.
1. Декораторы для функциональных представлений
Самый простой способ ограничить доступ — использовать декоратор login_required:
from django.contrib.auth.decorators import login_required
@login_required
def profile_view(request):
# Доступно только аутентифицированным пользователям
return render(request, 'profile.html')
Для более сложной логики используйте декоратор userpassestest:
from django.contrib.auth.decorators import user_passes_test
def is_staff_user(user):
return user.is_authenticated and user.is_staff
@user_passes_test(is_staff_user)
def staff_dashboard(request):
# Доступно только сотрудникам
return render(request, 'staff_dashboard.html')
Для проверки разрешений используйте декоратор permission_required:
from django.contrib.auth.decorators import permission_required
@permission_required('app.add_model')
def create_view(request):
# Доступно только пользователям с правом 'app.add_model'
return render(request, 'create.html')
# Проверка нескольких разрешений
@permission_required(['app.add_model', 'app.change_model'])
def advanced_view(request):
# Пользователь должен иметь оба разрешения
return render(request, 'advanced.html')
2. Миксины для классовых представлений
Для классовых представлений Django предоставляет аналогичные миксины:
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin, PermissionRequiredMixin
from .models import Article
class ArticleListView(ListView):
model = Article
# Доступно всем пользователям
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = Article
# Доступно только аутентифицированным пользователям
login_url = '/accounts/login/' # URL для перенаправления неаутентифицированных пользователей
class StaffArticleCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = Article
fields = ['title', 'content']
def test_func(self):
# Проверка, является ли пользователь сотрудником
return self.request.user.is_staff
def handle_no_permission(self):
# Кастомная обработка при отсутствии прав
return redirect('access_denied')
class ArticleUpdateView(PermissionRequiredMixin, UpdateView):
model = Article
fields = ['title', 'content']
permission_required = 'app.change_article'
3. Разрешения на уровне объекта
Django также поддерживает разрешения на уровне объекта через методы has_permission в моделях:
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
permissions = [
("publish_article", "Can publish article"),
("feature_article", "Can feature article on homepage"),
]
def user_can_edit(self, user):
# Автор или сотрудник может редактировать
return user == self.author or user.is_staff
def user_can_delete(self, user):
# Только автор или админ может удалить
return user == self.author or user.is_superuser
def user_can_view(self, user):
# Неопубликованные статьи видны только автору и сотрудникам
return self.published or user == self.author or user.is_staff
В представлении это можно использовать так:
class ArticleDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView):
model = Article
def test_func(self):
article = self.get_object()
return article.user_can_view(self.request.user)
4. Кастомные бэкенды разрешений
Для сложной логики авторизации можно создать кастомный бэкенд разрешений:
# myapp/permissions.py
class CustomPermissionBackend:
def has_perm(self, user_obj, perm, obj=None):
# Пример: проверка принадлежности к определенному отделу
if not user_obj.is_authenticated:
return False
if perm == 'app.special_action':
return hasattr(user_obj, 'department') and user_obj.department == 'special'
return False
def has_module_perms(self, user_obj, app_label):
return user_obj.is_authenticated
Добавьте этот бэкенд в AUTHENTICATION_BACKENDS в settings.py:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', # Стандартный бэкенд
'myapp.permissions.CustomPermissionBackend', # Наш кастомный бэкенд
]
Таким образом, Django предоставляет гибкую и многоуровневую систему разграничения доступа, которую можно адаптировать под любые требования вашего приложения. 🛡️
Аутентификация и авторизация — фундаментальные компоненты безопасности любого Django-приложения. Как мы рассмотрели, фреймворк предоставляет мощные инструменты для их реализации: от кастомных моделей пользователей до гибких механизмов разграничения прав. Ключ к успешной архитектуре безопасности — планирование на раннем этапе и глубокое понимание доступных компонентов Django. Начните с правильной модели пользователя, внедрите надежные формы входа и регистрации, а затем постройте многоуровневую систему разграничения прав, соответствующую потребностям вашего проекта. И помните: в вопросах безопасности лучше потратить больше времени на этапе проектирования, чем исправлять уязвимости в рабочем приложении.
Читайте также
- Настройка подключения к базе данных в Django: полное руководство
- Тестирование Django-приложений: методы, инструменты, стратегии
- Django миграции: полное руководство для веб-разработчиков
- Django деплой: от локальной разработки до боевого сервера – тонкости
- Система шаблонов Django: как использовать для создания динамических сайтов
- Установка Django: пошаговая инструкция для начинающих разработчиков
- Оптимизация Django ORM: техники повышения производительности запросов
- Профессиональный мониторинг Django-приложений: инструменты, практики
- Django: мощный веб-фреймворк на Python для разработчиков
- Лучшие сообщества Django-разработчиков: форумы, чаты, митапы


