• 3.1
  • 3.2
  • 6.1
  • Версия документации: 5.0

Расширяем модуль аутентификации Django

Система аутентификации, входящая в состав Django, отлично подойдёт для решения многих типичных задач, однако вам может не хватить функциональности, предоставляемой «из коробки». Для того, чтобы настроить аутентификацию под требования своего проекта сначала необходимо разобраться какие части этой системы могут быть расширены или заменены. В этом документе мы детально рассмотрим возможности настройки системы аутентификации.

Бэкенды аутентификации обеспечивают расширяемую систему для аутентификации в разных сервисах, в дополнение к стандартной для Django системе аутентификации через модель User.

Вы можете назначить вашим моделям собственные права доступа, которые могут быть проверены системой аутентификации Django.

Вы можете расширить стандартную модель User или полностью заменить эту модель.

Другие сервисы аутентификации

Бывают случаи когда вам необходимо подключиться к сторонним сервисам аутентификации, использующим альтернативные источники имён пользователей, паролей или иные методы аутентификации.

Например, в вашей компании используется система LDAP для хранения логинов и паролей для каждого сотрудника. Иметь разные аккаунты для LDAP и Django приложений не очень удобно, как для пользователей, так и для администраторов сети.

В такой ситуации возможно интегрировать систему аутентификации Django с другой системой аутентификации. Вы можете переопределить стандартную систему аутентификации Django или объединить её с другими системами.

Обратитесь к справочнику по бренду аутентификации для информации по бэкендам аутентификации, поставляемым с Django.

Бэкенды аутентификации

Система аутентификации Django поддерживает список бэкендов, которые она применяет в свой работе. Когда кто-то вызывает django.contrib.auth.authenticate() – в соответствии с документом Как авторизовать пользователя – Django пробует авторизовать пользователя с помощью бекэндов из списка. Если первый бэкенд не подошёл, Django пробует использовать второй и так далее пока не кончится список.

Список бэкендов аутентификации определён в параметре AUTHENTICATION_BACKENDS файла конфигурации в виде кортежа путей к классам Python’а, в которых определены методы аутентификации. Эти классы могут располагаться где угодно, лишь бы были доступны интерпретатору Python.

По умолчанию, AUTHENTICATION_BACKENDS устанавливается как:

["django.contrib.auth.backends.ModelBackend"]

Это базовый механизм аутентификации, который проверяет базу данных пользователей Django и запрашивает встроенные разрешения. Он не обеспечивает защиту от атак грубой силы с помощью какого-либо механизма ограничения скорости. Вы можете либо реализовать свой собственный механизм ограничения скорости в пользовательском бэкэнде аутентификации, либо использовать механизмы, предоставляемые большинством веб-серверов.

Также имеет значение порядок перечисления бэкендов в параметре конфигурации AUTHENTICATION_BACKENDS. Таким образом, если один логин и пароль совпадает в нескольких бэкендах аутентификации, то Django прекратит проверку на первом из них.

Если какой-либо бэкенд вызовет исключение PermissionDenied, процесс аутентификации немедленно остановится. В этом случае Django не будет пытаться проверить бэкенды, следующие по списку далее.

Примечание

После аутентификации пользователя Django сохраняет, какой бэкэнд использовался для аутентификации пользователя в сеансе пользователя, и повторно использует тот же бэкэнд на протяжении всего этого сеанса всякий раз, когда требуется доступ к текущему аутентифицированному пользователю. Фактически это означает, что источники аутентификации кэшируются для каждого сеанса, поэтому, если вы измените AUTHENTICATION_BACKENDS, вам придется очистить данные сеанса, если вам нужно заставить пользователей проходить повторную аутентификацию с использованием других методов. Простой способ сделать это — выполнить Session.objects.all().delete().

Создание бэкенда аутентификации

Бэкенд аутентификации - это класс, реализующий два обязательных метода: get_user(user_id) и authenticate(**credentials), а так же ряд необязательных прав, относящихся к методам аутентификации.

Метод get_user принимает параметр user_id, который может быть как именем пользователя, так и ID базы данных или чем-либо ещё, но передаваемое значение обязательно должно быть первичным ключом модели User, и возвращает объект User.

Метод authenticate принимает учётные данные в виде именованных аргументов. В основном, это будет выглядеть так:

from django.contrib.auth.backends import BaseBackend


class MyBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None):
        # Check the username/password and return a user.
        ...

Также метод может принимать токен, вот так:

from django.contrib.auth.backends import BaseBackend


class MyBackend(BaseBackend):
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...

В любом случае, метод authenticate должен проверить переданные ему учётные данные и вернуть объект User, соответствующий этим данным в случае их корректности. В другом случае он должен вернуть None.

request — это HttpRequest и может быть None, если он не был предоставлен authenticate() (который передает его на серверную часть).

Администратор Django тесно связан с объектом пользователя Django <user-objects>. Например, чтобы пользователь мог получить доступ к администратору, User.is_staff и User.is_active должны иметь значение True (подробности см. в разделе AdminSite.has_permission()).

Лучший способ справиться с этим — создать объект «Пользователь» Django для каждого пользователя, существующего в вашем бэкэнде (например, в вашем каталоге LDAP, внешней базе данных SQL и т. д.). Вы можете либо заранее написать сценарий, чтобы сделать это, либо ваш метод аутентификации может сделать это при первом входе пользователя в систему.

Вот пример серверной части, которая выполняет аутентификацию по переменной имени пользователя и пароля, определенной в вашем файле settings.py, и создает объект Django User при первой аутентификации пользователя. В этом примере созданный объект «Пользователь» Django является суперпользователем, который будет иметь полный доступ к администратору:

from django.conf import settings
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User


class SettingsBackend(BaseBackend):
    """
    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.

    Use the login name and a hash of the password. For example:

    ADMIN_LOGIN = 'admin'
    ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
    """

    def authenticate(self, request, username=None, password=None):
        login_valid = settings.ADMIN_LOGIN == username
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. There's no need to set a password
                # because only the password from settings.py is checked.
                user = User(username=username)  # is_active defaults to True.
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

Управление методами авторизации в своих бэкендах

Бэкенды аутентификации могут представлять дополнительные права доступа.

Модель пользователя передаст функции по проверке прав (get_group_permissions(), get_all_permissions(), has_perm() и has_module_perms()) любому бэкенду аутентификации, который их реализует.

Предоставленные пользователю права являются набором прав, представленных пользователю всеми бэкендами. Следовательно, Django представляет пользователю права, которые выдал хотя бы один бэкенд.

Если бэкенд вызовет исключение PermissionDenied в методах has_perm() или has_module_perms(), процесс авторизации будет немедленно остановлен и остальные бэкенды вызваны не будут.

Организовать проверку прав для простого бэкенда из примера выше довольно просто:

from django.contrib.auth.backends import BaseBackend


class MagicAdminBackend(BaseBackend):
    def has_perm(self, user_obj, perm, obj=None):
        return user_obj.username == settings.ADMIN_LOGIN

В примере, показанном выше, пользователю выдаётся полный набор прав доступа. Следует отметить, что в дополнение к передачи аргументов стандартных для функций django.contrib.auth.models.User, для всех функций аутентификации необходимо передавать объект пользователя, который может быть и анонимным.

Полная реализация бэкенда аутентификации может быть найдена в классе ModelBackend, определённом в файле `django/contrib/auth/backends.py`_, который является стандартным бэкендом и в основном работает с таблицей auth_permission. Если вам потребуется реализовать нестандартное поведение для определённой части API бэкендов, воспользуйтесь возможностями наследования в Python и унаследуйте ModelBackend, вместо реализации полного API в своём бэкенде.

Авторизация анонимных пользователей

Анонимным пользователем называют пользователя, который ещё не прошёл процедуру аутентификации, соответственно мы не имеем о нём никакой информации. Однако это не означает, что анонимные пользователи не могут пользоваться вашим приложением. Большинство сайтов позволяют анонимам просматривать информацию, некоторые даже разрешают оставлять анонимные комментарии.

В системе разрешений Django нет места для хранения разрешений для анонимных пользователей. Однако объект пользователя, передаваемый в серверную часть аутентификации, может быть объектом django.contrib.auth.models.AnonymousUser, позволяющим серверной части указывать собственное поведение авторизации для анонимных пользователей. Это особенно полезно для авторов многоразовых приложений, которые могут делегировать все вопросы авторизации авторизирующему бэкенду, вместо того, чтобы нуждаться в настройках, например, для контроля анонимного доступа.

Авторизация неактивных пользователей

Неактивным пользователем является тот, у которого в поле is_active установлено значение False. Серверы аутентификации ModelBackend и RemoteUserBackend запрещают аутентификацию этим пользователям. Если в пользовательской модели пользователя нет поля is_active, всем пользователям будет разрешено пройти аутентификацию.

Вы можете использовать AllowAllUsersModelBackend или AllowAllUsersRemoteUserBackend, если вы хотите разрешить неактивным пользователям проходить аутентификацию.

Поддержка анонимных пользователей в системе прав доступа позволяет реализовать сценарий, когда анонимные пользователи могут выполнять какие-либо действия в то время как неактивные авторизованные пользователи не могут этого делать.

Не забывайте проверять атрибут is_active в методах проверки правпользователей вашего бекэнда.

Обработка разрешений для объектов

В Django механизм управления правами подготовлен для работы с правамиобъектов, хотя и ещё не реализован в ядре фреймворка. Это означает, что проверкаправ объекта всегда будет возвращать False или пустой список (в зависимости от видавыполняемой проверки). Бэкенд аутентификации получает именованные параметры``obj`` и user_obj для каждого объекта использованного в методе авторизации и соответственноможет вернуть информацию о правах этого объекта.

Создаем пользовательские права доступа

Что бы создать пользовательские права доступа для вашей моделинеобходимо определить их в переменной permissions :ref:`атрибуте Meta<meta-options>`вашей модели.

В примере ниже описывается как создать пользовательсике права доступадля модели Task, другими словами вы определяеете что пользователь можетделать в вашем приложении, а что нет:

class Task(models.Model):
    ...

    class Meta:
        permissions = [
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        ]

Новые пользовательские права будут созданы после вызова manage.py migrate. Вашему приложению будетнеобходимо проверять эти значения каждый раз когда пользовательпытается получить доступ к функциям приложения (просмотр заданий,изменения статуса заданий, закрытие заданий). В продолжении выше описаногопримера, так вы можете проверить права пользователя для просмотра заданий:

user.has_perm("app.close_task")

Расширяем модель User

Существуюет два способа расширения стандартной моделиclass:~django.contrib.auth.models.User без замены модели на вашусобственную. Если вам нужно изменить только поведение моделибез измения данных вы можете создать proxy модель <proxy-models>`на основе модели :class:`~django.contrib.auth.models.User. С помощью модели proxyвы можете,добавить, добавить пользовательские менеджеры или методы сохранив стандартныефункции.

Если вы хотите хранить ддополнительную информацию относящуююся к модели``User`` вы можете использовать связь один к одному с полямимодели хранящей эту ифнормацию. Эту связанную модель часто называют профайлпользователя, так как она хранит информацию не относящююся к аутентификациипользователей. Например, вы можете создать модель Employee:

from django.contrib.auth.models import User


class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    department = models.CharField(max_length=100)

Предполагая, что у Фреда Смита есть сотрудник, у которого есть модель пользователя и сотрудника, вы можете получить доступ к связанной информации, используя стандартные соглашения о связанных моделях Django:

>>> u = User.objects.get(username="fsmith")
>>> freds_department = u.employee.department

Что бы добавить поля из модели профайла в интерфейс администраторанужно определить InlineModelAdmin в файле``admin.py`` вашего приложения (для этого примера используется:class:~django.contrib.admin.StackedInline), добавить его к классу ``UserAdmin``и заново зарегистрировать вместе с классом User

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User

from my_user_profile_app.models import Employee


# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
    model = Employee
    can_delete = False
    verbose_name_plural = "employee"


# Define a new User admin
class UserAdmin(BaseUserAdmin):
    inlines = [EmployeeInline]


# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Модель профайл это обычная модель Django. От других моделей ее отличаеттолько наличие свзяи один к одному с моделью User. Как правило записив этой модели не создаются автоматичски вместе с созданием пользователя,но вы можете воспользоваться методом :attr:`django.db.models.signals.post_save`для создания или обновления записей в профайле по мере необходимости.

Заметим, что использование связаных моделей приводит к увеличениюзапросов к базе данных и дополнительной нагрузке на нее, и, в зависиомтисот ваших потребностей, замена модели User на вашу собственную модельс нужными вам полями может быть лучшим выбором.

Заменяем стандартную модель User

Для некоторых проектов возможностей встроенной в Django модели:class:~django.contrib.auth.models.User будет недостаточно. Например,вам необходимо использовать в качестве идентификатора пользоавтеляemail адрес вместо имени пользователя.

Вы можете переписать стандартную модель User указав в настройках приложения AUTH_USER_MODEL ссылка на вашу модель:

AUTH_USER_MODEL = "myapp.MyUser"

Эта пунктирная пара описывает label приложения Django (которое должно быть в вашем INSTALLED_APPS) и имя модели Django, которую вы хотите использовать в качестве пользовательской модели.

Использование пользовательской модели пользователя при запуске проекта

Если вы начинаете новый проект, вы можете настроить собственную модель пользователя, которая будет вести себя идентично модели пользователя по умолчанию, создав подкласс AbstractUser:

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    pass

Не забудьте указать на него AUTH_USER_MODEL. Сделайте это перед созданием каких-либо миграций или первым запуском «manage.pymigration».

Кроме того, зарегистрируйте модель в файле admin.py приложения:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)

Переход на пользовательскую модель пользователя в середине проекта

Изменение AUTH_USER_MODEL после создания таблиц базы данных возможно, но может быть сложным, поскольку оно влияет, например, на внешние ключи и отношения «многие ко многим».

Изменение этой настройки после того как вы уже создали ваши таблицыне отразится в makemigrations и вам нужно будет вручную правитьсхему вашей БД, переносить данные из старой таблицы пользователей и,возможно, вручную применять некторые миграции.

Из-за ограничей в динамических зависимостях Django вам необходимоубедиться что заменяемая модель указанная в :setting:`AUTH_USER_MODEL`была создано в вашей первой миграции (обчно она называется 0001_initial).В противном случае у вас будут проблемы с зависимотями.

Кроме того вы можете столкнуться с CircularDependencyError когда запуститемиграцию, Django не сможет самостоятельно выйти из бесконечного цикла вызванногоавтоматическими зависимостями. Если вы видите эту ошибку вам необходимо определитьмодель ссылающуюся на старую модель User и исправить это в следующей миграции.Вы можете создать две обычные модели с внешними ключами ссылающимися друг на другаи, запустив makemigrations, увидеть что происходит когда появляются циклические зависимости.

Многоразовые приложения и AUTH_USER_MODEL

Приложения многократного использования не должны реализовывать пользовательскую модель пользователя. В проекте может использоваться множество приложений, и два приложения многократного использования, в которых реализована пользовательская модель пользователя, не могут использоваться вместе. Если вам нужно хранить информацию о каждом пользователе в вашем приложении, используйте ForeignKey или OneToOneField для settings.AUTH_USER_MODEL, как описано ниже.

Ссылка на модель User

Если вы ссылаетесь на модель на модель User`напрямую (например испльзую внешние ключи), ваш код не будет работать впроектах где стандартная модель заменена на другую в настройке:setting:`AUTH_USER_MODEL.

get_user_model()

Вместо того что бы ссылаться на модель get_user_model()`.Этот метод возвращает действующею модель – указаную в настройках приложенииили стандартную модель User, в случае если не изменялась.

Когда вы определяете в вашей модели пользователей внешние ключи илиотношения многие ко многим вы должны указывать параметр:setting: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. Например:

from django.conf import settings
from django.db.models.signals import post_save


def post_save_receiver(sender, instance, created, **kwargs):
    pass


post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)

Другими словами вы всегда должны ссылаться на пользовательскуюмодель используя настройку AUTH_USER_MODEL в вашем кодекоторая будет проверться во время импорта. ``get_user_model()` работаеттолько один раз, когда Django импортирует модели.

Если ваше приложение тестируется с использованием нескольких пользовательских моделей, например, с использованием @override_settings(AUTH_USER_MODEL=...), и вы кэшируете результат get_user_model() в переменной уровня модуля, вам может потребоваться прослушать сигнал setting_changed, чтобы очистить кеш. Например:

from django.apps import apps
from django.contrib.auth import get_user_model
from django.core.signals import setting_changed
from django.dispatch import receiver


@receiver(setting_changed)
def user_model_swapped(*, setting, **kwargs):
    if setting == "AUTH_USER_MODEL":
        apps.clear_cache()
        from myapp import some_module

        some_module.UserModel = get_user_model()

Определение пользовательской модели

Когда вы начинаете свой проект с пользовательской моделью пользователя, остановитесь и подумайте, является ли это правильным выбором для вашего проекта.

Хранение всей информации, связанной с пользователем, в одной модели устраняет необходимость в дополнительных или более сложных запросах к базе данных для извлечения связанных моделей. С другой стороны, может оказаться более подходящим хранить информацию о пользователе, специфичную для приложения, в модели, которая связана с вашей пользовательской моделью пользователя. Это позволяет каждому приложению указывать свои собственные требования к пользовательским данным без потенциального конфликта или нарушения предположений других приложений. Это также означает, что вы должны сохранить свою пользовательскую модель как можно более простой, сосредоточить внимание на аутентификации и следовать минимальным требованиям, которым Django ожидает, что пользовательские модели будут соответствовать.

Ваша модель хотя бы одно уникальное поле для идентификации.Это может быть имя пользователя, имейл адрес или любой другойуникальный атрибут.

Простейший способ построить модель совместимую с моделью User этонаследовать модель AbstractBaseUser.:class:~django.contrib.auth.models.AbstractBaseUser обеспечивает базовуюреализацию модели User, в том числе хэширование паролей и сброс пароляпосредством токенов.

class models.CustomUser
USERNAME_FIELD

Строка, описывающая имя поля в модели пользователя, которое используется в качестве уникального идентификатора. Обычно это какое-либо имя пользователя, но это также может быть адрес электронной почты или любой другой уникальный идентификатор. Поле должно быть уникальным (например, в его определении должно быть установлено unique=True), если только вы не используете собственный механизм аутентификации, который может поддерживать неуникальные имена пользователей.

В примере ниже поле identifier используется в качествеуникального идентификатора:

class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = "identifier"
EMAIL_FIELD

Строка, описывающая имя поля электронной почты в модели User. Это значение возвращается get_email_field_name().

REQUIRED_FIELDS

Список имен полей, которые будут запрашиваться при создании пользователяс использованием команды createsuperuser. Пользователю будетпредложено задать значение для каждого из этих полей. Этот список долженсодержать имена всех полей для которых атрибут blank уставновлен False и полядля которых этот атрибут не определен, а так же любые другие поля какие вы захотите.Изменение параметра REQUIRED_FIELDS ни как не отразится на остальных частяхфреймворка Django, таких как создание пользователя через панель администратора.

Пример ниже показывает как можно задать два обязательных поля –дата рождения и рост:

class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ["date_of_birth", "height"]

Примечание

В атрибуте REQUIRED_FIELDS вы можете задать любые обязательные полявашей модели User кроме USERNAME_FIELD и password. Эти поляявляются обязательными по умолчанию.

is_active

Логические атрибут указывающий является ли пользователь «активным».По умолчанию класс AbstractBaseUser устанавливает его в True. Выможете изменить это в вашем бекэнде аутентификации. Для подробностейсмотри документ атрибут is_active во встроеное модели ``User``

get_full_name()

Необязательный. Более длинный формальный идентификатор пользователя, например его полное имя. Если реализовано, оно отображается рядом с именем пользователя в истории объекта в django.contrib.admin.

get_short_name()

Необязательный. Короткий неофициальный идентификатор пользователя, например его имя. Если это реализовано, это заменяет имя пользователя в приветствии пользователя в заголовке django.contrib.admin.

Импорт AbstractBaseUser

AbstractBaseUser и BaseUserManager можно импортировать из django.contrib.auth.base_user, поэтому их можно импортировать без включения django.contrib.auth в INSTALLED_APPS.

Следующие методы доступны из любого класса наследующего:class:~django.contrib.auth.models.AbstractBaseUser:

class models.AbstractBaseUser
get_username()

Возвращает значение из поля указанного в качестве USERNAME_FIELD.

clean()

Нормализует имя пользователя, вызывая normalize_username(). Если вы переопределите этот метод, обязательно вызовите super(), чтобы сохранить нормализацию.

classmethod get_email_field_name()

Возвращает имя поля электронной почты, указанное атрибутом EMAIL_FIELD. По умолчанию используется 'email', если EMAIL_FIELD не указано.

classmethod normalize_username(username)

Применяет нормализацию Юникода NFKC к именам пользователей, чтобы визуально идентичные символы с разными кодовыми точками Юникода считались идентичными.

is_authenticated

Атрибут только для чтения, который всегда имеет значение True (в отличие от AnonymousUser.is_authenticated, который всегда имеет значение False). Это способ узнать, прошел ли пользователь аутентификацию. Это не подразумевает никаких разрешений и не проверяет, активен ли пользователь или имеет ли действительный сеанс. Несмотря на то, что обычно вы проверяете этот атрибут в request.user, чтобы узнать, был ли он заполнен AuthenticationMiddleware (представляющим текущего вошедшего в систему пользователя), вы должны знать, что этот атрибут имеет значение True для любого экземпляра User.

is_anonymous

Всегда возвращает False. Это способ дифференцировать от объектов:class:~django.contrib.auth.models.AnonymousUser. Обычно предпочтительнееиспользовать is_authenticated() метод.

set_password(raw_password)

Меняет пароль пользователя на переданный в параметре педварительнохэшировав его. Объект AbstractBaseUser не сохраняется.

Если используется метод:meth:~django.contrib.auth.models.AbstractBaseUser.set_unusable_password() и raw_password равен None пользователь будетпомечен как не использующий пароль.

check_password(raw_password)
acheck_password(raw_password)

Асинхронная версия: acheck_password()

Возвращает True если пароль указан верно (вычисляет хэш исравнивает его с хэшем хранимым в базе данных).

Changed in Django 5.0:

Добавлен метод acheck_password().

set_unusable_password()

Помечает пользователя как не использующего пароля. Но это не тожесамое что указывать пустую строку в качестве пароля. Если уставнолено тометод check_password()`никогда не вернет ``True`(). Объект :class:`~django.contrib.auth.models.AbstractBaseUser`не сохраняется.

Вам может это понадобиться если вы используете внешний источникданных для аутентифифкации, например, директорю LDAP.

has_usable_password()

Вернет False если для пользователя бул вызван метод:meth:~django.contrib.auth.models.AbstractBaseUser.set_unusable_password().

get_session_auth_hash()

Вернет HMAC (хэш) пароля. Используется для переопределения сессиипосле смены пароля.

get_session_auth_fallback_hash()

Возвращает HMAC поля пароля, используя SECRET_KEY_FALLBACKS. Используется get_user().

Работает с любым классом унаследованным от AbstractBaseUser

class models.AbstractUser
clean()

Нормализует электронную почту, вызывая BaseUserManager.normalize_email(). Если вы переопределите этот метод, обязательно вызовите super(), чтобы сохранить нормализацию.

Определение пользовательской модели

Вам так же необходимо определить собственный менеджер пользователейвашей модели User. Если ваше модель User определяет поля username,``email``, is_staff, is_active, is_superuser, last_login и date_joined так жеи в стандартной модели User вы можете использовать стандартный UserManager Django. Однако, если вы определили другиеполя в вашей модели вам необходим ваш собственный менеджер пользователйкоторый будет унаследован от :class:`~django.contrib.auth.models.BaseUserManager`и определять два обязательных метода:

class models.CustomUserManager
create_user(username_field, password=None, **other_fields)

Метод create_user() должен принимать вкачестве параметровимя пользователя плюс другие обязательные поля. Например,если ваша модель пользователей использует email в качествелогина с обязательным указанием даты рождения то ваш метод``create_user`` должен быть определен как:

def create_user(self, email, date_of_birth, password=None):
    # create user here
    ...
create_superuser(username_field, password=None, **other_fields)

Метод create_superuser() должен принимать вкачестве параметровимя пользователя плюс другие обязательные поля. Например,если ваша модель пользователей использует email в качествелогина с обязательным указанием даты рождения то ваш метод``create_superuser()`` должен быть определен как:

def create_superuser(self, email, date_of_birth, password=None):
    # create superuser here
    ...

Атрибут USERNAME_FIELD теперь поддеоживает внешние ключи.В связи с этим возникает проблема. При выполнении команды из:djadmin:createsuperuser из командной строки вы неможете передатьобъект связанного объекта, по этому вы можете просто указать простоID записи в БД (to_field указываетна ID по умолчанию).

BaseUserManager предоставляет следующие методы:

class models.BaseUserManager
classmethod normalize_email(email)

Это classmethod который используется для нормализации электронногоадреса путем преобразования доменного имени в нижний регистр.

get_by_natural_key(username)

Получает экземпляр пользователя, использую содержимое поля,указаного в USERNAME_FIELD.

Расширяем встроенную модель User

Если вас полностью устраивает модель Django User, но вы хотите добавить некоторую дополнительную информацию о профиле, вы можете создать подкласс django.contrib.auth.models.AbstractUser и добавить свои собственные поля профиля, хотя мы рекомендуем использовать отдельную модель, как описано в Определение пользовательской модели. AbstractUser обеспечивает полную реализацию стандартного User как абстрактную модель.

Встроенные формы авторизации

Встроенные в Django формы и:ref:представления <built-in-auth-views> делают определенные предположенияо модели User с которой они работают.

Следующие методы доступны из любого класса наследующего:class:~django.contrib.auth.models.AbstractBaseUser:

В следующих формах сделаны предположения о пользовательской модели, и их можно использовать без изменений, если эти предположения выполняются:

  • Предполагается что модель пользователя имеет поле с именем email,которое может быть использовано для идентификации пользователяи поле is_active хранящее булево значение для предотвращения сбросапароля для неактивных пользователей.

Зависит от User модели. Долженбыть переписан для любой новой пользовательской модели.

Если ваша пользовательская модель является подклассом AbstractUser, то вы можете расширить эти формы следующим образом:

from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser


class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ("custom_field",)

Пользовательская модель и django.contrib.admin

Если вы хотите что бы ваша пользовательская модель так же работала садминистративным интерфейсом она должна определять некторыеобязательные атрибуты и методы. Эти методы позволяют админ модулюконтролировать доступ пользователй к админской части приложения:

class models.CustomUser
is_staff

Возвращает True если пользователю разрешен доступ к админ сайту.

is_active

Возвращает True если пользователь активен.

has_perm(perm, obj=None):

Возвращает True если пользователь имеет указанное разрашение.Если obj поддерживается, разрешение должно быть проверено в отношениконктретного экземпляра объекта.

has_module_perms(app_label):

Возвращает True если пользователь имеет доступ к модели указанного приложения.

Вам так же надо зарегстрировать вашу пользовательскую модель дляадмин модуля. Если ваша модель наследует django.contrib.auth.models.AbstractUser``модель вы можете использовать ``django.contrib.auth.admin.UserAdmin класс Django.Однако, если вы наследуеете AbstractBaseUser классвам необходимо определить пользовательский класс ModelAdmin. Для этого выможете наследовать стандартный класс django.contrib.auth.admin.UserAdmin ипереопределить все ссылки на поля в django.contrib.auth.models.AbstractUser всоответсвии со структурой вашей модели.

Примечание

Если вы используете пользовательский ModelAdmin, который является подклассом django.contrib.auth.admin.UserAdmin, то вам необходимо добавить свои пользовательские поля в fieldsets (для полей, которые будут использоваться при редактировании пользователей) и в add_fieldsets (для полей, которые будут использоваться при создании пользователя). Например:

from django.contrib.auth.admin import UserAdmin


class CustomUserAdmin(UserAdmin):
    ...
    fieldsets = UserAdmin.fieldsets + ((None, {"fields": ["custom_field"]}),)
    add_fieldsets = UserAdmin.add_fieldsets + ((None, {"fields": ["custom_field"]}),)

См. полный пример <custom-users-admin-full-example> для получения более подробной информации.

Пользовательские права доступа

Что бы упростить подключения системы прав доступа фреймворка в вашпользовательский класс Django имеет класс PermissionsMixin. Это абстрактная модель которую вы можете включить в иерархиюклассов вашей пользовательской модели, предоставляющий вам доступ ко всемметодам и полям базы данных необходиых для работы модуля прав доступа.

PermissionsMixin предоставляют следуюющиеметоды и атрибуты:

class models.PermissionsMixin
is_superuser

Булев тип. Указывает что пользователь имеет все права без их явногоназначения.

get_user_permissions(obj=None)

Возвращает набор прав доступа групп в которых состоит пользователь.

Если передается obj возвращает персональные права доступа толькодля указанного объекта.

get_group_permissions(obj=None)

Возвращает набор прав доступа групп в которых состоит пользователь.

Если передается obj возвращает групповые права доступа толькодля указанного объекта.

get_all_permissions(obj=None)

Возвращает набор как групповых так и индивидуальных прав доступа.

Если передается obj возвращает персональные права доступа толькодля указанного объекта.

has_perm(perm, obj=None)

Возвращает True если пользователь имеет указанные права доступа.``perm`` указываются в формате "<app label>.<permission codename>" (дляподробностей смотри документ – права доступа).Если пользователь не активен будет всегда возвращать False.

Если передан obj, этот метод проверит права доступа толькодля указанного объекта.

has_perms(perm_list, obj=None)

Возвращает True если пользователь имеет все перечисленные пара доступапереданные в формате "<app label>.<permission codename>". Если пользователь не активен метод вернет False.

Если передан obj, этот метод проверит права доступа толькодля указанного объекта.

has_module_perms(package_name)

Вернет True если пользователь имеет какие либо права доступа дляуказанного пакета (приложения Django). Вернет False еслипользователь не активен.

PermissionsMixin и ModelBackend

Если вы не включаете класс PermissionsMixin вы должны убедиться, что не ссылаетесь на методыпроверки прав доступа определенные в ModelBackend. ``ModelBackend``предполагает что определнные поля доступны в вашей модели пользователя.И если ваша модель пользователей не имеет этих полей вы будете получатьошибки базы данных когда попытаетесь проверить права доступа.

Пользовательская модель User и Proxy модели

Одним из ограничений пользовательской модели User является то, что она сломает любые Proxy модели расширяющиеестандартную модель. Proxy модели должны основываться на конкретомбазовом классе. Определяя пользовательскую модель User вы лишаеетеDjango возможности конкрентно определить базовый класс.

Если в своем проекте вы используете Proxy модели вы должны либомодифицировать ее что бы она расширяла модель User, котораяиспользуется в ваше проекте, либо определить функции выполняемыеProxy моделями непосредственно вашей пользовательской модели.

Полный пример

Здесь вы можете посмотреть пример админ-совместимого приложенияуправления пользователями. Пользовательская модельиспользует, в качествеимени пользователя, поле admin и обязательное поле даты рождения. Такжеона не предоставлет никаких пользовательских прав, за исключением простого флага``admin``. Эта модель будет совместима со всеми встроенными формами и представлениями,за исключением формы создания пользователя. Этот пример показывает, как можноиспользовать много компонентов вместе не копируя их исходный код в ваше приложение.

Этот код будет полностью находится в файле models.py вашегоприлодения аутентификации:

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError("Users must have an email address")

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name="email address",
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["date_of_birth"]

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

Затем, что бы зарегистрировать вашу пользовательскую модель для панели администратора Django, нужно добавить следующий в файл``admin.py`` вашего приложения:

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from customauth.models import MyUser


class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""

    password1 = forms.CharField(label="Password", widget=forms.PasswordInput)
    password2 = forms.CharField(
        label="Password confirmation", widget=forms.PasswordInput
    )

    class Meta:
        model = MyUser
        fields = ["email", "date_of_birth"]

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    disabled password hash display field.
    """

    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ["email", "password", "date_of_birth", "is_active", "is_admin"]


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ["email", "date_of_birth", "is_admin"]
    list_filter = ["is_admin"]
    fieldsets = [
        (None, {"fields": ["email", "password"]}),
        ("Personal info", {"fields": ["date_of_birth"]}),
        ("Permissions", {"fields": ["is_admin"]}),
    ]
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = [
        (
            None,
            {
                "classes": ["wide"],
                "fields": ["email", "date_of_birth", "password1", "password2"],
            },
        ),
    ]
    search_fields = ["email"]
    ordering = ["email"]
    filter_horizontal = []


# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)

И, на конец, указать вашу пользотельскую модель в качестве моделипо умолчанию в файле settings.py (AUTH_USER_MODEL):

AUTH_USER_MODEL = "customauth.MyUser"
Back to Top