Настройка аутентификации в Django
Аутентификация, предоставляемая Django, подходит для большинства распространённых случаев, но у вас могут быть потребности, не удовлетворённые значениями по умолчанию. Настройка аутентификации в ваших проектах требует понимания, какие части предоставленной системы могут быть расширены или заменены. Этот документ содержит подробные сведения о том, как можно настроить систему аутентификации.
Модули аутентификации предоставляют расширяемую систему для случаев, когда имя пользователя и пароль, хранящиеся в модели пользователя, должны быть аутентифицированы с использованием другого сервиса, отличного от значения по умолчанию Django.
Вы можете добавить своим моделям собственные разрешения, которые могут быть проверены с помощью системы авторизации Django.
Вы можете расширить стандартную User модель или заменить полностью настроенной моделью.
Другие источники аутентификации
Иногда возникает необходимость подключиться к другому источнику аутентификации — то есть к другому источнику имён пользователей и паролей или методам аутентификации.
Например, ваша компания может уже иметь установленный LDAP, который хранит имя пользователя и пароль каждого сотрудника. Это было бы неудобно как для системного администратора сети, так и для самих пользователей, если бы пользователи имели отдельные учётные записи в LDAP и в приложениях на основе Django.
Поэтому, чтобы справиться с такими ситуациями, система аутентификации Django позволяет подключать другие источники аутентификации. Вы можете переопределить стандартную схему, основанную на базе данных Django, или использовать стандартную систему вместе с другими системами.
См. справочник по модулям аутентификации для получения информации о модулях аутентификации, включённых в Django.
Указание модулей аутентификации
Внутри Django поддерживается список «модулей аутентификации», которые проверяются для аутентификации. Когда кто-то вызывает django.contrib.auth.authenticate() — как описано в Руководстве по входу в систему — Django пытается выполнить аутентификацию по всем модулям аутентификации. Если первый метод аутентификации не удаётся, Django пытается использовать второй и так далее, пока не будут испробованы все модули.
Список используемых модулей аутентификации задаётся в настройке AUTHENTICATION_BACKENDS. Это должен быть список имён Python-путей, указывающих на классы 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(request, **credentials), а также набор необязательных методов, связанных с разрешениями методы авторизации.
Метод get_user принимает user_id — который может быть именем пользователя, идентификатором базы данных или чем-либо другим, но должен быть первичным ключом объекта пользователя — и возвращает объект пользователя или None.
Метод authenticate принимает аргумент request и данные для проверки подлинности в качестве аргументов ключевых слов. В большинстве случаев он будет выглядеть так:
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() должен проверить полученные данные для проверки подлинности и вернуть объект пользователя, соответствующий этим данным, если данные для проверки подлинности действительны. Если они недействительны, он должен вернуть None.
request — это HttpRequest и может быть None в том случае, если он не был передан в authenticate() (который передаёт его в модуль).
Админ-панель Django тесно связана с объектом пользователя Django объект пользователя. Лучший способ решения этой проблемы — создать объект Django User для каждого пользователя, который существует для вашего модуля (например, в вашем каталоге LDAP, вашей внешней базе данных SQL и т. д.). Вы можете либо написать скрипт для этого заранее, либо ваш метод authenticate может сделать это в первый раз при входе пользователя в систему.
Вот пример модуля аутентификации, который выполняет аутентификацию по имени пользователя и паролю, определённому в вашем файле settings.py и создаёт объект Django User в первый раз при аутентификации пользователя:
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)
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_user_permissions(), get_group_permissions(), get_all_permissions(), has_perm(), has_module_perms() и with_perm()) любому модулю аутентификации, который реализует эти функции.
Разрешения, предоставленные пользователю, будут представлять собой супермножество всех разрешений, возвращаемых всеми модулями. То есть Django предоставляет пользователю разрешение, которое предоставляет любой один модуль.
Если модуль вызывает исключение PermissionDenied в has_perm() или has_module_perms(), авторизация немедленно завершится неудачей, и Django не будет проверять последующие модули.
Модуль может реализовать разрешения для магической админ-панели так:
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.
Авторизация для анонимных пользователей
В рамках системы разрешений Django нет места для хранения разрешений для анонимных пользователей. Однако объект пользователя, переданный в модуль аутентификации, может быть объектом django.contrib.auth.models.AnonymousUser, что позволяет модулю указать поведение авторизации для анонимных пользователей. Это особенно полезно для авторов повторно используемых приложений, которые могут делегировать все вопросы авторизации модулю аутентификации, а не нуждаться в настройках, например, для управления доступом анонимных пользователей.
Авторизация неактивных пользователей
Вы можете использовать AllowAllUsersModelBackend или AllowAllUsersRemoteUserBackend, если хотите разрешить аутентификацию неактивных пользователей.
Поддержка анонимных пользователей в системе разрешений позволяет сценарий, в котором анонимные пользователи имеют права на выполнение определенных действий, в то время как неактивные авторизованные пользователи — нет.
Не забудьте проверить атрибут is_active пользователя в собственных методах разрешений бэкэнда.
Обработка разрешений на объекты
Фреймворк разрешений Django имеет основу для разрешений на объекты, хотя в ядре нет реализации для него. Это означает, что проверка разрешений на объекты всегда вернет False или пустой список (в зависимости от проведённой проверки). Бэкенд аутентификации получит ключевые параметры obj и user_obj для каждого метода авторизации, связанного с объектом, и может вернуть разрешение на уровне объекта соответствующим образом.
Настраиваемые разрешения
Для создания настраиваемых разрешений для заданного объекта модели используйте permissions атрибут модели Meta.
В этом примере Task модели создаются два пользовательских разрешения, то есть действия, которые пользователи могут или не могут выполнять с 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 (функция, которая создает разрешения, связана с сигналом post_migrate). Ваш код отвечает за проверку значения этих разрешений, когда пользователь пытается получить доступ к функциональности, предоставляемой приложением (изменение статуса задач или закрытие задач). Продолжая пример выше, следующий код проверяет, может ли пользователь закрыть задачи:
user.has_perm('app.close_task')
Расширение существующей модели User
Существует два способа расширения стандартной модели User, не заменяя собственную модель. Если необходимые изменения относятся только к поведению и не требуют изменений в хранящихся в базе данных данных, вы можете создать модель-прокси на основе User. Это позволяет использовать все функции, предлагаемые моделями-прокси, включая порядок сортировки по умолчанию, настраиваемые менеджеры или настраиваемые методы модели.
Если вы хотите сохранить информацию, относящуюся к User, вы можете использовать OneToOneField к модели, содержащей поля для дополнительной информации. Эта модель один к одному часто называется моделью профиля, поскольку она может хранить информацию, не относящуюся к аутентификации, о пользователе сайта. Например, вы можете создать модель 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)
Предполагая, что существует существующий сотрудник Фред Смит, у которого есть как модель User, так и модель Employee, вы можете получить доступ к связанной информации, используя стандартные соглашения Django для связанных моделей:
>>> u = User.objects.get(username='fsmith') >>> freds_department = u.employee.department
Чтобы добавить поля модели профиля на страницу пользователя в админке, определите InlineModelAdmin (в данном примере мы будем использовать StackedInline) в admin.py приложения и добавьте его в класс 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, которые имеют однозначную связь с моделью пользователя. Таким образом, они не создаются автоматически при создании пользователя, но может использоваться django.db.models.signals.post_save для создания или обновления связанных моделей по мере необходимости.
Использование связанных моделей приводит к дополнительным запросам или объединениям для получения связанных данных. В зависимости от ваших потребностей, настраиваемая модель пользователя, включающая связанные поля, может быть лучшим вариантом, однако существующие отношения с моделью пользователя по умолчанию в приложениях вашего проекта могут оправдать дополнительную нагрузку на базу данных.
Замена модели пользователя User
В некоторых проектах требования к аутентификации могут не подходить к встроенной модели пользователя Django User. Например, на некоторых сайтах в качестве маркера идентификации лучше использовать адрес электронной почты, а не имя пользователя.
Django позволяет переопределить модель пользователя по умолчанию, задав значение для настройки AUTH_USER_MODEL, которая ссылается на настраиваемую модель:
AUTH_USER_MODEL = 'myapp.MyUser'
Эта строка с точками описывает имя приложения Django (которое должно быть в вашем INSTALLED_APPS) и имя модели Django, которую вы хотите использовать в качестве модели пользователя.
Использование настраиваемой модели пользователя при запуске проекта
Если вы начинаете новый проект, настоятельно рекомендуется настроить настраиваемую модель пользователя, даже если стандартная модель User вам подходит. Эта модель ведет себя идентично модели пользователя по умолчанию, но в будущем вы сможете ее настроить, если возникнет такая необходимость:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Не забудьте указать AUTH_USER_MODEL на нее. Сделайте это до создания миграций или запуска manage.py migrate в первый раз.
Также зарегистрируйте модель в 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 после создания таблиц базы данных значительно сложнее, так как это затрагивает внешние ключи и многие-ко-многим отношения.
Это изменение нельзя выполнить автоматически и требует ручного исправления схемы, перемещения данных из старой таблицы пользователей и, возможно, ручного повторного применения некоторых миграций. См. #25313 для описания шагов.
Из-за ограничений динамической функции зависимости Django для взаимозаменяемых моделей, модель, на которую ссылается AUTH_USER_MODEL, должна быть создана в первой миграции её приложения (обычно называется 0001_initial); в противном случае у вас возникнут проблемы с зависимостями.
Кроме того, может возникнуть CircularDependencyError при выполнении миграций, так как Django не сможет автоматически разорвать цикл зависимости из-за динамической зависимости. Если вы видите эту ошибку, вы должны разорвать цикл, перенеся зависящие от вашей модели пользователя модели во вторую миграцию. (Вы можете попробовать создать две обычные модели, которые имеют ForeignKey друг к другу и посмотреть, как makemigrations разрешает эту циклическую зависимость, если хотите увидеть, как это обычно делается.)
Модули повторного использования и модель пользователя AUTH_USER_MODEL
Приложения повторного использования не должны реализовывать пользовательскую модель. Проект может использовать много приложений, и два приложения повторного использования, реализующие пользовательскую модель, не смогут работать вместе. Если вам нужно хранить информацию о пользователе в приложении, используйте ForeignKey или OneToOneField к settings.AUTH_USER_MODEL, как описано ниже.
Ссылка на модель User
Если вы ссылаетесь на User напрямую (например, путем ссылки на него во внешнем ключе), ваш код не будет работать в проектах, где настройка AUTH_USER_MODEL была изменена на другую модель пользователя.
-
get_user_model() -
Вместо прямой ссылки на
User, вы должны использовать ссылку на модель пользователя, используяdjango.contrib.auth.get_user_model(). Этот метод вернёт текущую активную модель пользователя — настроенную модель пользователя, если она указана, илиUserв противном случае.При определении внешних ключей или связей «многие ко многим» с моделью пользователя вы должны указать настроенную модель, используя параметр
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, поэтому вы можете использоватьmodels.ForeignKey(get_user_model(), ...).Если ваш проект тестируется с несколькими моделями пользователей, например, с использованием
@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(**kwargs): if kwargs['setting'] == 'AUTH_USER_MODEL': apps.clear_cache() from myapp import some_module some_module.UserModel = get_user_model()
Настройка пользовательской модели
При старте проекта с пользовательской моделью, стоит задуматься, подходит ли такой выбор для вашего проекта.
Хранение всей информации о пользователях в одной модели исключает необходимость дополнительных или более сложных баз данных для получения связанных моделей. С другой стороны, может быть более целесообразно хранить информацию о пользователях, специфичную для приложения, в модели, которая имеет отношение с вашей пользовательской моделью. Это позволяет каждому приложению указать свои собственные требования к данным о пользователе без потенциального конфликта или нарушения предположений другими приложениями. Это также означает, что вы сохраните свою модель пользователя максимально простой, сфокусированной на аутентификации и соответствующей минимальным требованиям, которые Django ожидает от настраиваемых моделей пользователей.
Если вы используете стандартный модуль аутентификации, то ваша модель должна иметь единственное уникальное поле, которое можно использовать для идентификации. Это может быть имя пользователя, адрес электронной почты или любой другой уникальный атрибут. Неуникальное поле имени пользователя разрешено, если вы используете настраиваемый модуль аутентификации, который может его поддерживать.
Самый простой способ создать совместимую настраиваемую модель пользователя — унаследовать от AbstractBaseUser. AbstractBaseUser предоставляет основную реализацию модели пользователя, включая хэшированные пароли и токенизированные сбросы паролей. Затем вам необходимо предоставить некоторые ключевые детали реализации:
-
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должен содержать все необходимые поля вашей модели пользователя, но не должен содержатьUSERNAME_FIELDилиpassword, так как эти поля всегда будут запрошены.
-
is_active -
Логический атрибут, указывающий, считается ли пользователь «активным». Этот атрибут предоставляется как атрибут для
AbstractBaseUserпо умолчаниюTrue. Способ вашей реализации будет зависеть от деталей выбранных модулей аутентификации. См. документациюis_active attribute on the built-in user modelдля получения дополнительной информации.
-
get_full_name() -
Необязательно. Более длинный формальный идентификатор пользователя, например, его полное имя. Если реализовано, это отображается рядом с именем пользователя в истории объекта в
django.contrib.admin.
-
get_short_name() -
Необязательно. Короткий, неформальный идентификатор пользователя, например, его имя. Если реализовано, это заменяет имя пользователя в приветствии пользователю в заголовке
django.contrib.admin.
Импорт
AbstractBaseUserAbstractBaseUserиBaseUserManagerимпортируются изdjango.contrib.auth.base_user, чтобы их можно было импортировать без включенияdjango.contrib.authвINSTALLED_APPS. -
Следующие атрибуты и методы доступны для любого подкласса AbstractBaseUser:
-
class models.AbstractBaseUser -
-
get_username() -
Возвращает значение поля, указанного в
USERNAME_FIELD.
-
clean() -
Нормализует имя пользователя, вызвав
normalize_username(). Если вы переопределяете этот метод, обязательно вызовитеsuper(), чтобы сохранить нормализацию.
-
classmethod get_email_field_name() -
Возвращает имя поля email, указанное атрибутом
EMAIL_FIELD. По умолчанию возвращает'email', еслиEMAIL_FIELDне указан.
-
classmethod normalize_username(username) -
Применяет Unicode-нормализацию NFKC к именам пользователей, чтобы визуально идентичные символы с разными кодами Unicode считались одинаковыми.
-
is_authenticated -
Только для чтения атрибут, который всегда
True(в отличие отAnonymousUser.is_authenticated, который всегдаFalse). Это способ определить, был ли пользователь аутентифицирован. Это не подразумевает никаких разрешений и не проверяет, активен ли пользователь или у него есть действительная сессия. Хотя обычно вы проверяете этот атрибут дляrequest.user, чтобы узнать, был ли он заполнен middlewareAuthenticationMiddleware(представляющий текущего вошедшего в систему пользователя), вы должны знать, что этот атрибутTrueдля любого экземпляраUser.
-
is_anonymous -
Только для чтения атрибут, который всегда
False. Это способ отличить объектыUserиAnonymousUser. Как правило, следует отдавать предпочтение использованиюis_authenticatedэтому атрибуту.
-
set_password(raw_password) -
Устанавливает пароль пользователя на заданную строку, обрабатывая хеширование пароля. Не сохраняет объект
AbstractBaseUser.Если raw_password равен
None, пароль будет установлен на непригодный, как если бы использовалсяset_unusable_password().
-
check_password(raw_password) -
Возвращает
True, если заданная строка является правильным паролем для пользователя. (Это учитывает хеширование пароля при сравнении).
-
set_unusable_password() -
Помечает пользователя как не имеющего установленного пароля. Это не то же самое, что иметь пустую строку в качестве пароля.
check_password()для этого пользователя никогда не вернетTrue. Не сохраняет объектAbstractBaseUser.Это может потребоваться, если аутентификация для вашего приложения происходит по внешнему источнику, например, каталогу LDAP.
-
has_usable_password() -
Возвращает
False, если для этого пользователя был вызванset_unusable_password().
-
get_session_auth_hash() -
Возвращает HMAC поля пароля. Используется для Отмены сессии при смене пароля.
Изменено в Django 3.1:Алгоритм хеширования был изменен на SHA-256.
-
AbstractUser наследуется от AbstractBaseUser:
-
class models.AbstractUser -
-
clean() -
Нормализует email, вызвав
BaseUserManager.normalize_email(). Если вы переопределяете этот метод, обязательно вызовитеsuper()для сохранения нормализации.
-
Написание менеджера для пользовательской модели
Вы также должны определить пользовательский менеджер для своей модели пользователя. Если ваша модель пользователя определяет поля username, email, is_staff, is_active, is_superuser, last_login, и date_joined так же, как и в стандартной модели Django, вы можете использовать менеджер UserManager; однако, если ваша модель пользователя определяет другие поля, вам нужно определить пользовательский менеджер, расширяющий BaseUserManager, предоставляя два дополнительных метода:
-
class models.CustomUserManager -
-
create_user(username_field, password=None, **other_fields) -
Прототип
create_user()должен принимать поле имени пользователя плюс все необходимые поля в качестве аргументов. Например, если ваша модель пользователя используетemailв качестве поля имени пользователя и имеетdate_of_birthкак обязательное поле, то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в качестве поля имени пользователя и имеетdate_of_birthкак обязательное поле, тоcreate_superuserдолжно быть определено как:def create_superuser(self, email, date_of_birth, password=None): # create superuser here ...
-
Для ForeignKey в USERNAME_FIELD или REQUIRED_FIELDS, эти методы получают значение to_field (по умолчанию это primary_key) существующего экземпляра.
BaseUserManager предоставляет следующие служебные методы:
-
class models.BaseUserManager -
-
classmethod normalize_email(email) -
Нормализует адреса email, переводя доменную часть адреса в нижний регистр.
-
get_by_natural_key(username) -
Возвращает экземпляр пользователя, используя содержимое поля, указанного в
USERNAME_FIELD.
-
make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789') -
Возвращает случайный пароль заданной длины и заданным строкой допустимых символов. Обратите внимание, что значение по умолчанию для
allowed_charsне содержит букв, которые могут вызвать путаницу у пользователя, включая:-
i,l,I, и1(строчная буква i, строчная буква L, заглавная буква i и цифра один) -
o,O, и0(строчная буква о, заглавная буква о и ноль)
-
-
Расширение стандартной модели пользователей Django User
Если модель пользователей Django User вас полностью устраивает, но вы хотите добавить дополнительную информацию о профиле, можно наследоваться от django.contrib.auth.models.AbstractUser и добавить свои пользовательские поля профиля, хотя мы рекомендуем использовать отдельную модель, как описано в примечании «Уточнения по проектированию модели» в Указание пользовательской модели. AbstractUser предоставляет полную реализацию стандартной модели User в виде абстрактной модели.
Пользователи с пользовательскими данными и встроенные формы авторизации
Встроенные формы форм и представления представлений Django делают некоторые предположения о модели пользователя, с которой они работают.
Следующие формы совместимы с любым подклассом AbstractBaseUser:
-
AuthenticationForm: Использует поле имени пользователя, указанное вUSERNAME_FIELD. SetPasswordFormPasswordChangeFormAdminPasswordChangeForm
Следующие формы делают предположения о модели пользователя и могут быть использованы как есть, если эти предположения соблюдены:
-
PasswordResetForm: Предполагает, что модель пользователя имеет поле, хранящее адрес электронной почты пользователя с именем, возвращаемымget_email_field_name()(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 django.contrib.auth.admin.UserAdmin. Однако, если ваша модель пользователя расширяет 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',)}),
)
См. полный пример для получения дополнительных подробностей.
Пользователи с пользовательскими данными и разрешения
Для удобства включения системы разрешений Django в собственном классе пользователя Django предоставляет PermissionsMixin. Это абстрактная модель, которую можно включить в иерархию классов вашей модели пользователя, предоставляя все методы и поля базы данных, необходимые для поддержки модели разрешений Django.
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>"(см. разрешения). ЕслиUser.is_activeиis_superuserобаTrue, этот метод всегда возвращаетTrue.Если
objпередан, этот метод не будет проверять разрешение для модели, а для этого конкретного объекта.
-
has_perms(perm_list, obj=None) -
Возвращает
True, если пользователь имеет каждое из указанных разрешений, где каждое разрешение имеет формат"<app label>.<permission codename>". ЕслиUser.is_activeиis_superuserобаTrue, этот метод всегда возвращаетTrue.Если
objпередан, этот метод не будет проверять разрешения для модели, а для конкретного объекта.
-
has_module_perms(package_name) -
Возвращает
True, если пользователь имеет какие-либо разрешения в данном пакете (метка приложения Django). ЕслиUser.is_activeиis_superuserобаTrue, этот метод всегда возвращаетTrue.
-
Настраиваемые пользователи и прокси-модели
Одним из ограничений настраиваемых моделей пользователей является то, что установка настраиваемой модели пользователя нарушит любую прокси-модель, расширяющую User. Прокси-модели должны быть основаны на конкретном базовом классе; определив настраиваемую модель пользователя, вы лишаете Django возможности надёжно идентифицировать базовый класс.
Если ваш проект использует прокси-модели, вы должны либо изменить прокси, чтобы он расширял модель пользователя, используемую в вашем проекте, либо объединить поведение вашего прокси в подкласс вашего User.
Полный пример
Вот пример настраиваемого приложения пользователя, совместимого с админкой. Эта модель пользователя использует адрес электронной почты в качестве имени пользователя и требует дату рождения; она не предоставляет проверки разрешений, кроме флага 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)
Наконец, укажите настраиваемую модель в качестве модели пользователя по умолчанию для вашего проекта, используя настройку AUTH_USER_MODEL в вашем settings.py:
AUTH_USER_MODEL = 'customauth.MyUser'
В более старых версиях ReadOnlyPasswordHashField по умолчанию не disabled и UserChangeForm.clean_password() требуется для возврата начального значения, независимо от введённого пользователем.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/topics/auth/customizing/