Аутентификация в Django: пользователи, вход и права
Как устроена аутентификация в Django: модель User, вход и выход, LoginView, login_required, права и группы, своя модель пользователя и django-allauth.
Содержание · 14 разделов
- Как устроена система аутентификации
- Модель User: поля и основные методы
- get_user_model() и AUTH_USER_MODEL
- Своя модель пользователя (AUTH_USER_MODEL)
- Вход по email вместо username
- Вход и выход: готовые представления
- Шаблон страницы входа (LoginView)
- Куда перенаправлять после входа и выхода
- Выход только через POST
- Вход в своём представлении: authenticate() и login()
- Регистрация пользователей
- Ограничение доступа: login_required и LoginRequiredMixin
- Закрыть весь сайт: LoginRequiredMiddleware
- Права и группы
- Проверка прав в представлениях и шаблонах
- Сброс пароля по email
- Аутентификация в API
- django-allauth: регистрация, email и соцсети
- Частые ошибки
- После входа — 404 на /accounts/profile/
- 405 Method Not Allowed при выходе
- Manager isn’t available; ‘auth.User’ has been swapped
- TemplateDoesNotExist: registration/login.html
- Право выдано, а has_perm() возвращает False
- InconsistentMigrationHistory после добавления AUTH_USER_MODEL
- Чек-лист
- Частые вопросы
- Как разрешить вход по email, не меняя модель пользователя?
- Как сделать галочку «Запомнить меня»?
- Как отправлять письма сброса пароля через SMTP?
- Как войти под пользователем в тестах?
- Как защитить вход от перебора паролей?
- Итог
Аутентификация в Django встроена во фреймворк: приложение django.contrib.auth даёт модель пользователя User, хеширование паролей, вход и выход через сессии, готовые представления для логина и сброса пароля, а также систему прав и групп. В типовом проекте почти ничего не нужно писать с нуля — достаточно подключить готовые части и оформить шаблоны.
Быстрый ответ: добавьте path("accounts/", include("django.contrib.auth.urls")) в urls.py, создайте шаблон registration/login.html и закройте нужные страницы декоратором @login_required. Ниже — как это устроено, как работать с пользователями и правами, зачем заводить свою модель пользователя в самом начале проекта и когда подключать django-allauth. Примеры проверены на Django 5.2 и 6.x.
Как устроена система аутентификации
В проекте, созданном командой startproject, всё уже подключено. Проверьте settings.py:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth", # пользователи, группы, права
"django.contrib.contenttypes", # нужен для прав: право привязано к модели
"django.contrib.sessions",
# ...
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
# ...
]
Как это работает вместе:
- Пользователь отправляет логин и пароль. Функция
authenticate()проверяет их через бэкенды изAUTHENTICATION_BACKENDS(по умолчаниюModelBackend— поиск в базе). - Функция
login()записывает ID пользователя в сессию, а браузер получает cookiesessionid. - На каждом запросе
AuthenticationMiddlewareчитает сессию и кладёт пользователя вrequest.user. Для анонимного посетителя это объектAnonymousUser.
Поэтому в любом представлении и шаблоне доступен текущий пользователь:
def dashboard(request):
if request.user.is_authenticated:
...
AuthenticationMiddleware должен стоять после SessionMiddleware — подробнее о порядке в руководстве по middleware.
Модель User: поля и основные методы
Стандартная модель django.contrib.auth.models.User содержит поля:
| Поле | Назначение |
|---|---|
username | логин, уникальный, обязательный |
password | хеш пароля (не сам пароль) |
email, first_name, last_name | необязательные данные профиля |
is_active | неактивный пользователь не может войти |
is_staff | доступ в админку |
is_superuser | все права без явного назначения |
last_login, date_joined | даты последнего входа и регистрации |
groups, user_permissions | группы и индивидуальные права |
Создавайте пользователей через менеджер — он хеширует пароль:
>>> from django.contrib.auth import authenticate, get_user_model
>>> User = get_user_model()
>>> user = User.objects.create_user("anna", email="anna@example.com", password="s3cret-pass")
>>> user.password
'pbkdf2_sha256$1500000$...' # алгоритм$итерации$соль$хеш
>>> user.check_password("s3cret-pass")
True
>>> authenticate(username="anna", password="s3cret-pass")
<User: anna>
>>> authenticate(username="anna", password="wrong") # → None
Число итераций PBKDF2 растёт с версиями Django: 1 000 000 в 5.2, 1 200 000 в 6.0, 1 500 000 в 6.1. Старые хеши продолжают работать и пересчитываются при следующем входе пользователя. Сменить пароль — user.set_password("новый") и затем user.save(). Первого администратора создают командой createsuperuser, её варианты разобраны в статье «Как создать суперпользователя в Django».
Важно:
User.objects.create(username="bad", password="plain")сохранит пароль открытым текстом, и войти с ним не получится —authenticate()вернётNone. Для пользователей всегда используйтеcreate_user()илиset_password().
get_user_model() и AUTH_USER_MODEL
Не импортируйте User напрямую в коде приложений. Модель пользователя может быть заменена (см. следующий раздел), поэтому:
- в коде —
get_user_model(); - во внешних ключах моделей — строка
settings.AUTH_USER_MODEL.
from django.conf import settings
from django.db import models
class Article(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Своя модель пользователя (AUTH_USER_MODEL)
Для новых проектов Django рекомендует сразу заводить свою модель пользователя, даже если стандартной пока хватает. Позже это позволит добавить поля (телефон, аватар, настройки) без лишних таблиц и join’ов.
Важно: задайте
AUTH_USER_MODELдо первой командыmigrate. Поменять модель пользователя в проекте с существующими таблицами и данными очень сложно: на неё ссылаются внешние ключи, права, сессии и журнал админки, аmakemigrationsне сделает этот переход автоматически. Если проект уже в работе — храните дополнительные данные в модели профиля со связьюOneToOneFieldна пользователя.
Самый простой вариант — наследование от AbstractUser: все стандартные поля и поведение сохраняются.
python manage.py startapp accounts
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
phone = models.CharField("Телефон", max_length=20, blank=True)
# settings.py
INSTALLED_APPS += ["accounts"]
AUTH_USER_MODEL = "accounts.User" # "<приложение>.<Модель>"
python manage.py makemigrations accounts
python manage.py migrate
Зарегистрируйте модель в админке на основе стандартного UserAdmin, чтобы сохранить форму смены пароля и права:
# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
@admin.register(User)
class CustomUserAdmin(UserAdmin):
fieldsets = UserAdmin.fieldsets + (("Дополнительно", {"fields": ["phone"]}),)
add_fieldsets = UserAdmin.add_fieldsets + ((None, {"fields": ["phone"]}),)
Вход по email вместо username
Если логином должен быть email, уберите username и замените менеджер — стандартный UserManager требует username:
# accounts/models.py
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError("Email обязателен")
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_user(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self._create_user(email, password, **extra_fields)
class User(AbstractUser):
username = None
email = models.EmailField("Email", unique=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = [] # поля, которые спросит createsuperuser, кроме email и пароля
objects = UserManager()
После этого createsuperuser спрашивает email, а стандартные LoginView и authenticate(username=..., password=...) принимают email в поле логина. Учтите: normalize_email() приводит к нижнему регистру только домен (Ivan@Example.COM → Ivan@example.com). Стандартный UserAdmin в этом случае не подойдёт как есть: manage.py check выдаст ошибку admin.E033 из-за ordering = ("username",). Переопределите ordering, list_display, search_fields, fieldsets и add_fieldsets, заменив username на email.
Полный контроль над полями даёт AbstractBaseUser с PermissionsMixin, но тогда придётся описать больше кода самостоятельно. Выбор между двумя базовыми классами, настройка UserAdmin и смена модели в работающем проекте — в статье «Своя модель пользователя в Django». Подробнее о полях и Meta — в статье про модели Django.
Вход и выход: готовые представления
Самый быстрый способ — подключить все представления django.contrib.auth одной строкой:
# config/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
]
Вы получите маршруты:
| URL | Имя | Шаблон |
|---|---|---|
accounts/login/ | login | registration/login.html |
accounts/logout/ | logout | registration/logged_out.html |
accounts/password_change/ | password_change | registration/password_change_form.html |
accounts/password_change/done/ | password_change_done | registration/password_change_done.html |
accounts/password_reset/ | password_reset | registration/password_reset_form.html |
accounts/password_reset/done/ | password_reset_done | registration/password_reset_done.html |
accounts/reset/<uidb64>/<token>/ | password_reset_confirm | registration/password_reset_confirm.html |
accounts/reset/done/ | password_reset_complete | registration/password_reset_complete.html |
Если подключён django.contrib.admin, шаблоны для смены и сброса пароля Django возьмёт из админки (в её оформлении). А registration/login.html нужно создать самостоятельно — иначе будет TemplateDoesNotExist.
Шаблон страницы входа (LoginView)
Укажите папку шаблонов проекта и создайте templates/registration/login.html:
# settings.py
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # ← добавьте папку шаблонов проекта
"APP_DIRS": True,
# "OPTIONS": без изменений
},
]
<!-- templates/registration/login.html -->
<h1>Вход</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="next" value="{{ next }}">
<button type="submit">Войти</button>
</form>
<a href="{% url 'password_reset' %}">Забыли пароль?</a>
LoginView передаёт в шаблон форму AuthenticationForm и параметр next — адрес, куда вернуть пользователя после входа.
Куда перенаправлять после входа и выхода
# settings.py
LOGIN_URL = "login" # куда отправлять неавторизованных (имя маршрута или путь)
LOGIN_REDIRECT_URL = "/" # куда после входа, если нет ?next=
LOGOUT_REDIRECT_URL = "/" # куда после выхода
По умолчанию LOGIN_REDIRECT_URL равен /accounts/profile/. Если такой страницы нет, после успешного входа вы увидите 404 — частая ловушка новичков.
Выход только через POST
Начиная с Django 5.0 LogoutView принимает только POST: ссылка <a href="/accounts/logout/"> вернёт 405 Method Not Allowed. Делайте выход формой:
{% if user.is_authenticated %}
<p>Вы вошли как {{ user.username }}</p>
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit">Выйти</button>
</form>
{% else %}
<a href="{% url 'login' %}">Войти</a>
{% endif %}
Переменная user доступна во всех шаблонах благодаря контекст-процессору django.contrib.auth.context_processors.auth, который включён по умолчанию.
Вход в своём представлении: authenticate() и login()
Если нужна своя логика (например, вход по одноразовому коду), используйте функции напрямую:
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import redirect, render
def login_view(request):
if request.method == "POST":
user = authenticate(
request,
username=request.POST["username"],
password=request.POST["password"],
)
if user is not None:
login(request, user)
return redirect("/")
return render(request, "login.html", {"error": "Неверный логин или пароль"})
return render(request, "login.html")
def logout_view(request):
if request.method == "POST":
logout(request)
return redirect("/")
authenticate() возвращает None и для неверного пароля, и для пользователя с is_active=False. Если пароль меняется в своём представлении, вызовите update_session_auth_hash(request, user), иначе текущая сессия станет недействительной.
Регистрация пользователей
Готовой страницы регистрации в Django нет, но есть форма UserCreationForm с проверкой пароля валидаторами из AUTH_PASSWORD_VALIDATORS. Её Meta.model указывает на стандартный auth.User, поэтому со своей моделью форму нужно унаследовать:
# accounts/forms.py
from django.contrib.auth.forms import UserCreationForm
from .models import User
class SignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ["username", "email"]
# accounts/views.py
from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import SignUpForm
class SignUpView(CreateView):
form_class = SignUpForm
template_name = "registration/signup.html"
success_url = reverse_lazy("login")
# config/urls.py
from accounts.views import SignUpView
urlpatterns += [path("accounts/signup/", SignUpView.as_view(), name="signup")]
Для пароля 123 форма вернёт три ошибки: пароль слишком короткий, слишком распространённый и состоит только из цифр. Подтверждение email, вход через соцсети и прочее проще получить из django-allauth (см. ниже).
Ограничение доступа: login_required и LoginRequiredMixin
Для функций — декоратор, для классов — миксин:
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from django.views.generic import TemplateView
@login_required
def profile(request):
return HttpResponse(f"Привет, {request.user.username}")
class ProfileView(LoginRequiredMixin, TemplateView):
template_name = "accounts/profile.html"
Анонимный пользователь получит редирект на LOGIN_URL с параметром next: /accounts/login/?next=/accounts/profile/. LoginRequiredMixin должен стоять в списке родителей первым — левее TemplateView.
Закрыть весь сайт: LoginRequiredMiddleware
С Django 5.1 можно требовать вход для всех страниц сразу и открывать отдельные явно:
# settings.py
MIDDLEWARE += ["django.contrib.auth.middleware.LoginRequiredMiddleware"]
from django.contrib.auth.decorators import login_not_required
@login_not_required
def about(request):
...
Страница входа LoginView уже помечена как открытая. Middleware должен идти после AuthenticationMiddleware.
Права и группы
Для каждой модели Django автоматически создаёт четыре права: add_<модель>, change_<модель>, delete_<модель> и view_<модель>. Свои права добавляются в Meta:
class Book(models.Model):
# ...
class Meta:
permissions = [("publish_book", "Может публиковать книги")]
Проверка — строкой "<приложение>.<codename>":
>>> from django.contrib.auth.models import Group, Permission
>>> user = User.objects.get(username="ivan")
>>> perm = Permission.objects.get(codename="change_book", content_type__app_label="library")
>>> user.user_permissions.add(perm)
>>> user.has_perm("library.change_book")
False # права закешированы в объекте user
>>> user = User.objects.get(pk=user.pk)
>>> user.has_perm("library.change_book")
True
Права удобнее выдавать через группы — роль описывается один раз:
>>> editors, _ = Group.objects.get_or_create(name="Редакторы")
>>> editors.permissions.add(
... Permission.objects.get(codename="publish_book"),
... Permission.objects.get(codename="view_book", content_type__app_label="library"),
... )
>>> user.groups.add(editors)
>>> user = User.objects.get(pk=user.pk)
>>> sorted(user.get_all_permissions())
['library.change_book', 'library.publish_book', 'library.view_book']
Правила проверки: суперпользователь получает True на любое право, неактивный пользователь — всегда False, анонимный — False.
Проверка прав в представлениях и шаблонах
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
@permission_required("library.change_book", raise_exception=True)
def edit_book(request, pk):
...
class BookPublishView(PermissionRequiredMixin, TemplateView):
permission_required = "library.publish_book"
template_name = "library/publish.html"
С raise_exception=True декоратор сразу отдаёт 403. Без него пользователя без права отправят на страницу входа. PermissionRequiredMixin перенаправляет на вход анонимных пользователей, а вошедшим без права отдаёт 403.
В шаблоне права доступны через переменную perms:
{% if perms.library.change_book %}
<a href="{% url 'book_edit' book.pk %}">Редактировать</a>
{% endif %}
Для произвольных условий есть @user_passes_test и UserPassesTestMixin — например, проверка, что пользователь — автор объекта. Кеш прав, объектные права и типичные ловушки has_perm разобраны в статье о правах доступа и группах в Django. Права из этой системы использует и админка: как выдать редакторам доступ к отдельным моделям, разобрано в руководстве по Django Admin.
Сброс пароля по email
Маршруты password_reset уже подключены через django.contrib.auth.urls. Не хватает только отправки почты. Для разработки выведите письма в консоль:
# settings.py, Django 5.2 и 6.0
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
В Django 6.1 появилась настройка MAILERS — словарь почтовых бэкендов по аналогии с DATABASES и CACHES. EMAIL_BACKEND и остальные EMAIL_* в 6.1 продолжают работать, но выдают предупреждение об устаревании. Проект, созданный startproject в 6.1, уже содержит такой блок:
# settings.py, Django 6.1
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.console.EmailBackend",
},
}
Задавать MAILERS вместе с любой из старых настроек EMAIL_* нельзя: Django остановится с ошибкой ImproperlyConfigured.
Django отправляет письмо со ссылкой reset/<uidb64>/<token>/, только если пользователь с таким email существует, активен и у него задан пароль. При этом ответ одинаковый в обоих случаях — это защита от перебора адресов.
Аутентификация в API
Сессии и cookie подходят для сайта. Для мобильных приложений и SPA в Django REST Framework используют токены или JWT, а права описывают классами permission_classes. Как это настроить — в руководстве по Django REST Framework.
django-allauth: регистрация, email и соцсети
django-allauth закрывает то, чего нет во встроенной системе: регистрацию с подтверждением email, вход по email, вход через GitHub, Google, VK, Яндекс и других провайдеров, а также двухфакторную аутентификацию.
python -m pip install "django-allauth[socialaccount]"
# settings.py
INSTALLED_APPS += [
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.github",
]
MIDDLEWARE += ["allauth.account.middleware.AccountMiddleware"]
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
]
ACCOUNT_LOGIN_METHODS = {"email"}
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
# config/urls.py
urlpatterns += [path("accounts/", include("allauth.urls"))]
python manage.py migrate
allauth добавит страницы /accounts/login/, /accounts/signup/, /accounts/logout/, /accounts/password/reset/ и /accounts/github/login/. Ключи OAuth-приложения провайдера задаются в SOCIALACCOUNT_PROVIDERS или через админку. Не подключайте django.contrib.auth.urls и allauth.urls на один префикс — маршруты будут конфликтовать. Пример проверен на django-allauth 65.19 с Django 6.1; в старых версиях настройки назывались иначе (например, ACCOUNT_AUTHENTICATION_METHOD), сверяйтесь с документацией своей версии.
Актуальные версии django-allauth работают без django.contrib.sites и SITE_ID — в примере выше их нет. Если фреймворк сайтов нужен (например, несколько доменов в одном проекте), добавьте его до первого migrate: от этого зависит схема таблиц socialaccount.
Подтверждение почты, провайдеры VK ID, Яндекс и Telegram, headless-режим для SPA и двухфакторная аутентификация разобраны в отдельной статье «django-allauth: регистрация и вход через соцсети».
Частые ошибки
После входа — 404 на /accounts/profile/
Не задан LOGIN_REDIRECT_URL, и Django использует значение по умолчанию /accounts/profile/. Укажите свой адрес в settings.py.
405 Method Not Allowed при выходе
С Django 5.0 выход работает только через POST. Замените ссылку на форму с {% csrf_token %}.
Manager isn’t available; ‘auth.User’ has been swapped
Код импортирует django.contrib.auth.models.User, хотя в проекте своя модель. Замените импорт на get_user_model(), а внешние ключи — на settings.AUTH_USER_MODEL.
TemplateDoesNotExist: registration/login.html
Django не поставляет шаблон страницы входа. Создайте его в папке из TEMPLATES["DIRS"] или в templates/registration/ одного из приложений.
Право выдано, а has_perm() возвращает False
Права кешируются в объекте пользователя при первой проверке. Перезагрузите пользователя из базы (User.objects.get(pk=...)) — в новом запросе права подтянутся автоматически. Также проверьте, что пользователь активен.
InconsistentMigrationHistory после добавления AUTH_USER_MODEL
Модель пользователя заменили после первого migrate. На новом проекте проще пересоздать базу данных и миграции. На рабочем — оставьте стандартную модель и используйте профиль с OneToOneField.
Чек-лист
- своя модель пользователя и
AUTH_USER_MODELзаданы до первой миграции - в коде —
get_user_model(), во внешних ключах —settings.AUTH_USER_MODEL - пользователи создаются через
create_user(), пароли — черезset_password() - есть шаблон
registration/login.html, заданыLOGIN_REDIRECT_URLиLOGOUT_REDIRECT_URL - выход — POST-формой с CSRF-токеном
- закрытые страницы защищены
@login_required,LoginRequiredMixinилиLoginRequiredMiddleware - права выдаются через группы, а не суперпользователям «на всякий случай»
- для продакшна настроена отправка почты для сброса пароля
Частые вопросы
Как разрешить вход по email, не меняя модель пользователя?
Напишите свой бэкенд аутентификации, который ищет пользователя по email, и поставьте его в AUTHENTICATION_BACKENDS перед стандартным:
# accounts/backends.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
User = get_user_model()
try:
user = User.objects.get(email__iexact=username)
except (User.DoesNotExist, User.MultipleObjectsReturned):
return None
if user.check_password(password) and self.user_can_authenticate(user):
return user
return None
# settings.py
AUTHENTICATION_BACKENDS = [
"accounts.backends.EmailBackend",
"django.contrib.auth.backends.ModelBackend",
]
Теперь в форму входа можно ввести и email, и username. В стандартной модели email не уникален — при двух совпадениях бэкенд вернёт None, поэтому следите за уникальностью при регистрации.
Как сделать галочку «Запомнить меня»?
По умолчанию сессия живёт SESSION_COOKIE_AGE = 1 209 600 секунд (две недели). Если галочка не отмечена, сделайте сессию до закрытия браузера:
from django.contrib.auth.views import LoginView
class RememberLoginView(LoginView):
def form_valid(self, form):
response = super().form_valid(form)
if not self.request.POST.get("remember"):
self.request.session.set_expiry(0) # до закрытия браузера
return response
В шаблон входа добавьте <input type="checkbox" name="remember"> и подключите это представление вместо стандартного маршрута login.
Как отправлять письма сброса пароля через SMTP?
В Django 6.1 параметры SMTP передаются в OPTIONS почтового бэкенда:
import os
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.smtp.EmailBackend",
"OPTIONS": {
"host": "smtp.yandex.ru",
"port": 465,
"username": "robot@example.com",
"password": os.environ["SMTP_PASSWORD"],
"use_ssl": True,
},
},
}
DEFAULT_FROM_EMAIL = "robot@example.com"
В Django 5.2 и 6.0 те же значения задают настройками EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD и EMAIL_USE_SSL. Пароль храните в переменной окружения, а не в коде.
Как войти под пользователем в тестах?
Метод тестового клиента force_login() создаёт сессию без проверки пароля и без запроса к форме входа:
class ProfileTests(TestCase):
def test_profile_page(self):
user = User.objects.create_user("anna", password="s3cret-pass")
self.client.force_login(user)
response = self.client.get("/accounts/profile/")
self.assertEqual(response.status_code, 200)
Если нужно проверить саму форму входа, используйте self.client.login(username=..., password=...) или POST на страницу входа.
Как защитить вход от перебора паролей?
Встроенного ограничения попыток входа в Django нет. Его добавляют пакетом django-axes (блокировка по числу неудачных попыток), лимитом запросов на уровне веб-сервера или middleware. Для админки дополнительно помогает нестандартный адрес и двухфакторная аутентификация — подробнее в статье «Защита Admin URL».
Итог
django.contrib.auth закрывает основу: пользователи с хешированными паролями, вход и выход через сессии, готовые представления, права и группы. Главное архитектурное решение — своя модель пользователя — принимается в начале проекта, всё остальное можно наращивать постепенно. Для регистрации с подтверждением email и входа через соцсети подключайте django-allauth, для API — токены DRF.
Дальше: настройте доступ сотрудников в Django Admin, защитите вход в неё по статье «Защита Admin URL» и постройте API по руководству по DRF. Все материалы кластера — в хабе «Аутентификация и права в Django». Справочник — в документации Django по аутентификации.
- #Django
- #Аутентификация
- #django.contrib.auth
- #User
- #Права доступа
- #allauth