Настройка аутентификации в Django ¶
Аутентификации, поставляемой с 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
создание объекта своему методу User
при каждом первом подключении.
Вот пример механизма, который аутентифицируется на основе переменных имени пользователя и пароля, определенных в вашем файле, settings.py
и создает объект 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)
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
в Джанго / вно / авт / backends.py , который является механизмом по умолчанию и в большинстве запросов к таблице auth_permission
.
Авторизация для анонимных пользователей ¶
Анонимный пользователь - это пользователь, который не прошел аутентификацию, то есть не предоставил никаких действительных данных аутентификации. Однако это не обязательно означает, что он не получает никакого разрешения. На самом базовом уровне большинство веб-сайтов позволяют анонимным пользователям просматривать большинство страниц на сайте, а некоторые также разрешают комментарии и т. Д.
Система разрешений Django не предоставляет места для хранения разрешений для анонимных пользователей. Однако объект пользователя, переданный механизму аутентификации, может быть объектом, который django.contrib.auth.models.AnonymousUser
позволяет подсистеме определять поведение авторизации, специфичное для анонимных пользователей. Это особенно полезно для авторов многоразовых приложений, которые могут делегировать все вопросы разрешений механизму аутентификации, вместо того, чтобы, например, требовать настройки для управления правами анонимного доступа.
Авторизация для неактивных пользователей ¶
Неактивный пользователь - это пользователь, в поле is_active
которого установлено значение False
. Механизмы аутентификации ModelBackend
и RemoteUserBackend
запрещают этим пользователям проходить аутентификацию. Если в настраиваемом пользовательском шаблоне нет поля is_active
, всем пользователям будет разрешена аутентификация.
Вы можете использовать AllowAllUsersModelBackend
или, AllowAllUsersRemoteUserBackend
если хотите разрешить неактивным пользователям проходить аутентификацию.
Поддержка анонимных пользователей в системе разрешений позволяет представить сценарий, в котором анонимные пользователи имеют определенные разрешения, которых нет у неактивных аутентифицированных пользователей.
Не забудьте протестировать атрибут пользователя is_active
в методах вашего собственного механизма разрешений.
Управление разрешениями на объекты ¶
Система разрешений Django закладывает основу для разрешений на объекты, хотя в ядре Django нет конкретной реализации. Это означает, что проверка разрешений объекта всегда возвращает False
или пустой список (в зависимости от выполненной проверки). Механизм аутентификации получает именованные параметры obj
и user_obj
для каждого метода авторизации, привязанного к объектам, и может при необходимости возвращать разрешения уровня объекта.
Пользовательские разрешения ¶
Чтобы создать собственные разрешения для данного объекта модели, используйте « Мета-атрибут permissions
» модели .
Этот пример шаблона 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
кастомную модель ¶
Некоторые типы проектов имеют требования к аутентификации, для которых User
встроенная модель Django не всегда подходит. Например, некоторые сайты предпочитают использовать адрес электронной почты в качестве идентификатора, а не имя пользователя.
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(), ...)
Если ваше приложение тестируется с несколькими пользовательскими моделями, например using
@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
предоставляет базовую реализацию модели пользователя, включая хешированные пароли и токены сброса пароля. Затем вам необходимо предоставить важные детали реализации:
-
класс
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, например, при создании пользователя через интерфейс администратора.Новое в Django 3.0:REQUIRED_FIELDS
Теперь поддерживает поляManyToManyField
без специального промежуточного шаблона. Поскольку нет возможности передавать экземпляры моделей во время диалога сcreatesuperuser
, ожидается, что пользователь введет идентификаторы существующих экземпляров класса, на который указывает модель.Например, вот частичное определение модели пользователя, определяющее два обязательных поля, дату рождения и рост:
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
по умолчанию. Как вы его реализуете, будет зависеть от деталей выбранных механизмов аутентификации. См. Документацию по встроенной пользовательской модели для получения более подробной информации.attribut is_active
-
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
.-
Следующие методы и атрибуты доступны для каждого подкласса AbstractBaseUser
:
-
класс
models.
AbstractBaseUser
¶ -
get_username
() ¶ Возвращает значение поля, указанного в
USERNAME_FIELD
.
-
clean
() ¶ Нормализует имя пользователя при звонке
normalize_username()
. Если вы переопределите этот метод, обязательно вызовите,super()
чтобы сохранить нормализацию.
-
classmethod
get_email_field_name
() ¶ Возвращает имя поля электронной почты, обозначенного атрибутом
EMAIL_FIELD
. ЕслиEMAIL_FIELD
не указано, возвращается'email'
по умолчанию.
-
classmethod
normalize_username
( имя пользователя ) ¶ Применяет нормализацию Unicode NFKC к именам пользователей, чтобы визуально идентичные символы с разными кодовыми точками Unicode считались идентичными.
-
is_authenticated
¶ Атрибут только для чтения, который всегда действителен
True
(в отличие отAnonymousUser.is_authenticated
всегда действительногоFalse
). Это один из способов узнать, прошел ли пользователь аутентификацию. Никакие разрешения не принимаются во внимание, и нет контроля над флагомis_active
пользователя или действительностью сеанса. Хотя с этим атрибутом обычно обращаются, чтобыrequest.user
определить, был ли он установленAuthenticationMiddleware
(представляя текущего пользователя, вошедшего в систему), вы должны знать, что этот атрибут действителен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
:
-
класс
models.
AbstractUser
¶ -
clean
() ¶ Нормализует адрес электронной почты при звонке
BaseUserManager.normalize_email()
. Если вы переопределите этот метод, обязательно вызовите,super()
чтобы сохранить нормализацию.
-
Написание обработчика для пользовательской модели пользователя ¶
Вы также должны определить собственный менеджер для вашей пользовательской модели. Если он определяет поля username
, email
, is_staff
, is_active
, is_superuser
, last_login
и date_joined
сравним с пользователя по умолчанию модели в Django, вы можете использовать менеджер UserManager
Django. Однако, если ваша пользовательская модель определяет разные поля, вам нужно будет определить собственный обработчик, который наследуется от BaseUserManager
и предоставляет два дополнительных метода:
-
класс
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
предоставляет следующие служебные методы:
-
класс
models.
BaseUserManager
¶ -
classmethod
normalize_email
( электронная почта ) ¶ Нормализует адреса электронной почты, делая часть имени домена строчными буквами.
-
get_by_natural_key
( имя пользователя ) ¶ Извлекает пользовательский экземпляр, используя содержимое поля, указанного в
USERNAME_FIELD
.
-
make_random_password
( длина = 10 , allowed_chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789' ) ¶ Возвращает случайный пароль указанной длины, используя символы из допустимой строки символов. Обратите внимание, что значение по умолчанию
allowed_chars
не содержит непонятных букв, например:i
,l
,I
И1
(я маленькая, строчные буквы L, капитала я и число 1)o
,O
и0
(строчная o, прописная o и ноль)
-
classmethod
Расширение User
модели Django по умолчанию ¶
Если User
вас устраивает шаблон Django, но вы хотите добавить дополнительную информацию о профиле, создайте подкласс django.contrib.auth.models.AbstractUser
и добавьте свои собственные поля профиля. Однако рекомендуется создать отдельный шаблон, как описано в примечании «Особенности дизайна шаблона» в разделе « Указание настраиваемого пользовательского шаблона» . AbstractUser
обеспечивает полную реализацию модели по User
умолчанию в виде абстрактной модели .
Пользовательские пользователи и встроенные формы аутентификации ¶
Эти формы и виды , включенные в Django имеют определенные ожидания относительно пользовательской модели , с которыми они работают.
Следующие формы совместимы со всеми подклассами AbstractBaseUser
:
AuthenticationForm
: использует поле имени пользователя, обозначенноеUSERNAME_FIELD
.SetPasswordForm
PasswordChangeForm
AdminPasswordChangeForm
Следующие формы имеют определенные ожидания в отношении модели пользователя и могут использоваться как есть, если эти ожидания оправдаются:
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
Если вы хотите, чтобы ваш настраиваемый пользовательский шаблон также работал в интерфейсе администратора, ему необходимо определить некоторые дополнительные атрибуты и методы. Эти методы позволяют сайту администрирования контролировать доступ пользователей к его контенту:
-
класс
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
. Это абстрактная модель, которую вы можете добавить в иерархию классов вашей пользовательской модели и, таким образом, предоставить вам все необходимые методы и поля базы данных для поддержки модели разрешений пользовательской модели. Джанго.
PermissionsMixin
содержит следующие методы и атрибуты:
-
класс
models.
PermissionsMixin
¶ -
is_superuser
¶ Логическое значение. Указывает, что у этого пользователя есть все разрешения, без необходимости их явно назначать.
-
get_user_permissions
( obj = Нет ) ¶ - Новое в Django 3.0.
Возвращает набор разрешений (строк), которые пользователь получает напрямую.
Если
obj
передан, возвращает только разрешения пользователя, связанные с этим конкретным объектом.
-
get_group_permissions
( obj = Нет ) ¶ Возвращает набор разрешений (строк), которые пользователь получает через группы, к которым он / она принадлежит.
Если
obj
передан, возвращает только разрешения группы, связанные с этим конкретным объектом.
-
get_all_permissions
( obj = Нет ) ¶ Возвращает набор разрешений (строк), которые пользователь получает напрямую или через группы, к которым он принадлежит.
Если
obj
передан, возвращает только разрешения, связанные с этим конкретным объектом.
-
has_perm
( perm , obj = None ) ¶ Возвращает, есть
True
ли у пользователя указанное разрешение, где указаноperm
в формате (см. Разрешения ). Если и оба равны , этот метод всегда возвращает ."<étiquette application>.<code permission>"
User.is_active
is_superuser
True
True
Если
obj
передано, этот метод проверяет разрешение не на уровне модели, а для указанного объекта.
-
has_perms
( perm_list , obj = Нет ) ¶ Возвращает, есть
True
ли у пользователя все указанные разрешения, где каждое разрешение указано в формате . Если и оба равны , этот метод всегда возвращает ."<étiquette application>.<code permission>"
User.is_active
is_superuser
True
True
Если
obj
передано, этот метод управляет разрешениями не на уровне модели, а для указанного объекта.
-
has_module_perms
( имя_пакета ) ¶ Возвращает, есть
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
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
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'