Django-Admin.ru

Аутентификация в Django: пользователи, вход и права

Как устроена аутентификация в Django: модель User, вход и выход, LoginView, login_required, права и группы, своя модель пользователя и django-allauth.

Редакция Django-Admin.ru
· обновлено · 16 мин чтения

Содержание · 14 разделов
  1. Как устроена система аутентификации
  2. Модель User: поля и основные методы
  3. get_user_model() и AUTH_USER_MODEL
  4. Своя модель пользователя (AUTH_USER_MODEL)
  5. Вход по email вместо username
  6. Вход и выход: готовые представления
  7. Шаблон страницы входа (LoginView)
  8. Куда перенаправлять после входа и выхода
  9. Выход только через POST
  10. Вход в своём представлении: authenticate() и login()
  11. Регистрация пользователей
  12. Ограничение доступа: login_required и LoginRequiredMixin
  13. Закрыть весь сайт: LoginRequiredMiddleware
  14. Права и группы
  15. Проверка прав в представлениях и шаблонах
  16. Сброс пароля по email
  17. Аутентификация в API
  18. django-allauth: регистрация, email и соцсети
  19. Частые ошибки
  20. После входа — 404 на /accounts/profile/
  21. 405 Method Not Allowed при выходе
  22. Manager isn’t available; ‘auth.User’ has been swapped
  23. TemplateDoesNotExist: registration/login.html
  24. Право выдано, а has_perm() возвращает False
  25. InconsistentMigrationHistory после добавления AUTH_USER_MODEL
  26. Чек-лист
  27. Частые вопросы
  28. Как разрешить вход по email, не меняя модель пользователя?
  29. Как сделать галочку «Запомнить меня»?
  30. Как отправлять письма сброса пароля через SMTP?
  31. Как войти под пользователем в тестах?
  32. Как защитить вход от перебора паролей?
  33. Итог

Аутентификация в 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",
    # ...
]

Как это работает вместе:

  1. Пользователь отправляет логин и пароль. Функция authenticate() проверяет их через бэкенды из AUTHENTICATION_BACKENDS (по умолчанию ModelBackend — поиск в базе).
  2. Функция login() записывает ID пользователя в сессию, а браузер получает cookie sessionid.
  3. На каждом запросе 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/loginregistration/login.html
accounts/logout/logoutregistration/logged_out.html
accounts/password_change/password_changeregistration/password_change_form.html
accounts/password_change/done/password_change_doneregistration/password_change_done.html
accounts/password_reset/password_resetregistration/password_reset_form.html
accounts/password_reset/done/password_reset_doneregistration/password_reset_done.html
accounts/reset/<uidb64>/<token>/password_reset_confirmregistration/password_reset_confirm.html
accounts/reset/done/password_reset_completeregistration/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
↑ ↓ выборEnter открытьEsc закрыть