Настройка аутентификации в 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(**credentials), а также набор необязательных методов, связанных с разрешениями методы авторизации.
Метод get_user принимает user_id — это может быть имя пользователя, идентификатор базы данных или что-либо еще, но это должен быть первичный ключ вашего объекта пользователя — и возвращает объект пользователя.
Метод authenticate принимает данные для аутентификации в качестве ключевых аргументов. В большинстве случаев он будет выглядеть так:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a user.
...
Но он также может аутентифицировать токен, например:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a user.
...
В любом случае, authenticate() должен проверить предоставленные данные для аутентификации и вернуть объект пользователя, соответствующий этим данным, если данные являются допустимыми. Если они недействительны, он должен вернуть None.
Админ-панель Django тесно связана с объектом пользователя Django. Лучший способ справиться с этим — создать объект Django User для каждого пользователя, который существует для вашего модуля (например, в вашем каталоге LDAP, вашей внешней базе данных SQL и т. д.). Вы можете либо написать скрипт для этого заранее, либо метод authenticate может сделать это в первый раз при входе пользователя в систему.
Вот пример модуля аутентификации, который выполняет аутентификацию по имени пользователя и паролю, определённым в вашем файле settings.py , и создаёт объект Django User в первый раз при аутентификации пользователя:
from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
class SettingsBackend(object):
"""
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, 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_group_permissions(), get_all_permissions(), has_perm() и has_module_perms()) любому модулю аутентификации, который реализует эти функции.
Разрешения, предоставленные пользователю, будут супермножеством всех разрешений, возвращаемых всеми модулями. То есть, Django предоставляет пользователю разрешение, которое предоставляет любой из модулей.
Если модуль возвращает исключение PermissionDenied в методе has_perm() или has_module_perms(), авторизация немедленно завершится неудачей, и Django не будет проверять последующие модули.
Простой модуль выше может реализовать разрешения для магического администратора довольно просто:
class SettingsBackend(object):
...
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, позволяя модулю указать пользовательское поведение авторизации для анонимных пользователей. Это особенно полезно для авторов многократно используемых приложений, которые могут делегировать все вопросы авторизации модулю аутентификации, а не нуждаться в настройках, например, для управления доступом анонимных пользователей.
Авторизация для неактивных пользователей
Вы можете использовать AllowAllUsersModelBackend или AllowAllUsersRemoteUserBackend, если хотите разрешить аутентификацию неактивных пользователей.
Поддержка анонимных пользователей в системе разрешений позволяет сценарий, в котором анонимные пользователи имеют разрешения на выполнение определённых действий, в то время как неактивные авторизованные пользователи — нет.
Не забудьте проверить атрибут is_active пользователя в собственных методах разрешений бэкэнда.
В более старых версиях бэкэнд ModelBackend разрешал аутентификацию неактивных пользователей.
id="handling-object-permissions">Обработка разрешений на объекты
Фреймворк разрешений Django имеет основу для разрешений на объекты, хотя в ядре нет его реализации. Это означает, что проверка разрешений на объекты всегда вернёт значение False или пустой список (в зависимости от выполняемой проверки). Аутентификационный бэкэнд получит ключевые параметры obj и user_obj для каждого метода авторизации, относящегося к объекту, и может вернуть разрешение на уровне объекта, как это необходимо.
id1">Настраиваемые разрешения
Для создания настраиваемых разрешений для заданного объекта модели используйте атрибут permissions атрибут модели Meta.
В этом примере модель Task создаёт три настраиваемые разрешения, т. е. действия, которые пользователи могут или не могут выполнять с экземплярами Task, специфичные для вашего приложения:
class Task(models.Model):
...
class Meta:
permissions = (
("view_task", "Can see available tasks"),
("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.view_task')
id="extending-user">Расширение существующей 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)
Предполагая, что существует существующий Employee Фред Смит, у которого есть как модель 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.
Использование связанных моделей приводит к дополнительным запросам или соединениям для получения связанных данных. В зависимости от ваших потребностей, пользовательская модель, которая включает связанные поля, может быть лучшим вариантом, однако существующие связи с моделью пользователя по умолчанию в приложениях вашего проекта могут оправдать дополнительную нагрузку на базу данных.
id="auth-custom-user">Замена настраиваемой User модели
В некоторых проектах требования к аутентификации могут не соответствовать встроенной модели User Django. Например, на некоторых сайтах в качестве идентификатора лучше использовать адрес электронной почты, а не имя пользователя.
Django позволяет переопределить модель пользователя по умолчанию, задав значение для параметра AUTH_USER_MODEL, которое ссылается на пользовательскую модель:
AUTH_USER_MODEL = 'myapp.MyUser'
Эта строка с точками описывает имя приложения Django (которое должно быть в INSTALLED_APPS) и имя модели Django, которую вы хотите использовать в качестве модели пользователя.
id="using-a-custom-user-model-when-starting-a-project">Использование настраиваемой модели пользователя при запуске проекта
Если вы начинаете новый проект, настоятельно рекомендуется настроить пользовательскую модель, даже если модель User по умолчанию вам подходит. Эта модель ведет себя идентично модели пользователя по умолчанию, но вы сможете её настроить в будущем, если возникнет необходимость:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Не забудьте установить для параметра AUTH_USER_MODEL ссылку на неё. Сделайте это до создания миграций или запуска manage.py migrate в первый раз.
id="changing-to-a-custom-user-model-mid-project">Изменение модели пользователя во время проекта
Изменение параметра AUTH_USER_MODEL после создания таблиц базы данных значительно сложнее, так как это влияет на внешние ключи и связи «многие ко многим», например.
Это изменение не может быть выполнено автоматически и требует ручного исправления схемы, переноса данных из старой таблицы пользователей и, возможно, ручного повторного применения некоторых миграций. См. #25313 для описания шагов.
Из-за ограничений динамической функции зависимости Django для взаимозаменяемых моделей модель, на которую ссылается AUTH_USER_MODEL, должна быть создана в первой миграции своего приложения (обычно 0001_initial); в противном случае у вас возникнут проблемы с зависимостями.
Кроме того, при запуске миграций может возникнуть ошибка CircularDependencyError, так как Django не сможет автоматически разорвать цикл зависимостей из-за динамической зависимости. Если вы видите эту ошибку, вам следует разорвать цикл, перенеся модели, от которых зависит ваша модель пользователя, во вторую миграцию. (Вы можете попробовать создать две обычные модели, у которых есть ForeignKey друг к другу и посмотреть, как makemigrations разрешает этот циклический зависимость, если хотите увидеть, как это обычно делается.)
id="reusable-apps-and-auth-user-model">Многоразовые приложения и AUTH_USER_MODEL
Многоразовые приложения не должны реализовывать настраиваемую модель пользователя. Проект может использовать множество приложений, и два многоразовых приложения, реализующих настраиваемую модель пользователя, не могут использоваться вместе. Если вам необходимо хранить информацию на пользователя в вашем приложении, используйте ForeignKey или OneToOneField для settings.AUTH_USER_MODEL, как описано ниже.
id="referencing-the-user-model">Ссылка на модель User
Если вы напрямую ссылаетесь на User (например, ссылаясь на неё во внешнем ключе), ваш код не будет работать в проектах, где параметр AUTH_USER_MODEL был изменён на другую модель пользователя.
-
get_user_model()[source] -
Вместо прямой ссылки на
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 импортировал все модели.
Определение пользовательской модели
Рекомендации по проектированию модели
Внимательно обдумайте, прежде чем обрабатывать информацию, не напрямую связанную с аутентификацией, в вашей пользовательской модели.
Возможно, лучше хранить информацию о пользователе, специфичную для приложения, в модели, имеющей отношение к модели пользователя. Это позволит каждому приложению указывать свои собственные требования к данным пользователя без риска конфликтов с другими приложениями. С другой стороны, запросы для извлечения этой связанной информации будут включать соединение базы данных, что может повлиять на производительность.
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'USERNAME_FIELDтеперь поддерживаетForeignKey. Поскольку нет способа передать экземпляры модели во время запросаcreatesuperuser, ожидайте, что пользователь введёт значениеto_field(по умолчаниюprimary_key) существующего экземпляра.
-
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, так как эти поля всегда будут запрашиваться.REQUIRED_FIELDSтеперь поддерживаетForeignKey. Поскольку нет способа передать экземпляры модели во время запросаcreatesuperuser, ожидайте, что пользователь введёт значениеto_field(по умолчаниюprimary_key) существующего экземпляра.
-
is_active -
Булевый атрибут, который указывает, считается ли пользователь «активным». Этот атрибут предоставляется как атрибут для
AbstractBaseUserпо умолчаниюTrue. Как вы выберите его реализацию, будет зависеть от деталей выбранных вами механизмов аутентификации. Смотрите документацию дляis_active attribute on the built-in user modelдля подробностей.
-
get_full_name() -
Более длинный формальный идентификатор пользователя. Распространённой интерпретацией этого было бы полное имя пользователя, но это может быть любая строка, идентифицирующая пользователя.
-
get_short_name() -
Короткий, неформальный идентификатор пользователя. Распространённой интерпретацией этого было бы имя пользователя, но это может быть любая строка, идентифицирующая пользователя неформальным способом. Он также может возвращать то же значение, что и
django.contrib.auth.models.User.get_full_name().
Импортирование
AbstractBaseUserНовое в Django 1.9.AbstractBaseUserиBaseUserManagerимпортируются изdjango.contrib.auth.base_user, чтобы их можно было импортировать без включенияdjango.contrib.authвINSTALLED_APPS(в более старых версиях это вызывало предупреждение об устаревании и больше не поддерживается в Django 1.9). -
Следующие атрибуты и методы доступны для любого подкласса AbstractBaseUser:
-
class models.AbstractBaseUser -
-
get_username() -
Возвращает значение поля, указанного в
USERNAME_FIELD.
-
clean() -
Добавлена в Django 1.10.
Нормализует имя пользователя, вызвав
normalize_username(). Если вы переопределяете этот метод, обязательно вызывайтеsuper(), чтобы сохранить нормализацию.
-
classmethod normalize_username(username) -
Добавлена в Django 1.10.
Применяет нормализацию Unicode NFKC к именам пользователей, чтобы визуально идентичные символы с различными кодами Unicode считались идентичными.
-
is_authenticated -
Только для чтения атрибут, который всегда
True(в отличие отAnonymousUser.is_authenticated, который всегдаFalse). Это способ определить, был ли пользователь аутентифицирован. Это не подразумевает каких-либо разрешений и не проверяет, активен ли пользователь или имеет ли он действительную сессию. Несмотря на то, что обычно вы проверяете этот атрибут вrequest.user, чтобы узнать, был ли он заполнен middlewareAuthenticationMiddleware(представляющий текущего вошедшего в систему пользователя), вы должны знать, что этот атрибутTrueдля любого экземпляраUser.Изменено в Django 1.10:В более старых версиях это был метод. Поддержка обратной совместимости для использования его как метода будет удалена в Django 2.0.
-
is_anonymous -
Атрибут только для чтения, который всегда
False. Это способ различения объектовUserиAnonymousUser. Как правило, вы должны предпочесть использованиеis_authenticatedэтому атрибуту.Изменено в Django 1.10:В более старых версиях это был метод. Поддержка обратной совместимости для использования его как метода будет удалена в Django 2.0.
-
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 поля пароля. Используется для Отмены сессии при смене пароля.
-
Также следует определить пользовательский менеджер для вашей модели пользователя. Если ваша модель пользователя определяет поля username, email, is_staff, is_active, is_superuser, last_login, и date_joined так же, как и у стандартного пользователя Django, вы можете просто установить менеджер 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, **other_fields) -
Прототип
create_superuser()должен принимать поле имени пользователя, плюс все необходимые поля в качестве аргументов. Например, если ваша модель пользователя используетemailв качестве поля имени пользователя и имеетdate_of_birthв качестве обязательного поля, тоcreate_superuserдолжно быть определено как:def create_superuser(self, email, date_of_birth, password): # create superuser here ...В отличие от
create_user(),create_superuser()обязательно требует от вызывающей стороны предоставить пароль.
-
BaseUserManager предоставляет следующие вспомогательные методы:
-
class models.BaseUserManager -
-
classmethod normalize_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(строчная буква o, прописная буква o и ноль)
-
-
Расширение стандартной модели пользователя Django
Если вы полностью удовлетворены моделью пользователя Django User и хотите только добавить дополнительную информацию о профиле, вы можете просто унаследовать от django.contrib.auth.models.AbstractUser и добавить свои пользовательские поля профиля, хотя мы рекомендуем отдельную модель, как описано в примечании «Учетные записи пользователей» в Указание пользовательской модели. AbstractUser предоставляет полную реализацию стандартной модели User в виде абстрактной модели.
Пользователи и встроенные формы аутентификации
Встроенные формы Django форм и представлений делают некоторые предположения о модели пользователя, с которой они работают.
Следующие формы совместимы с любым подклассом AbstractBaseUser:
-
AuthenticationForm: Использует поле имени пользователя, указанное вUSERNAME_FIELD. SetPasswordFormPasswordChangeFormAdminPasswordChangeForm
Следующие формы предполагают модель пользователя и могут использоваться без изменений, если эти предположения выполняются:
-
PasswordResetForm: Предполагает, что модель пользователя имеет поле с именем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, которые отсутствуют в вашем пользовательском классе.
Пользователи пользовательского типа и разрешения
Чтобы легко включить систему разрешений Django в свой собственный класс пользователя, Django предоставляет PermissionsMixin. Это абстрактная модель, которую вы можете включить в иерархию классов для вашей модели пользователя, предоставив все необходимые методы и поля базы данных для поддержки модели разрешений Django.
PermissionsMixin предоставляет следующие методы и атрибуты:
-
class models.PermissionsMixin -
-
is_superuser -
Булево значение. Обозначает, что у данного пользователя есть все разрешения без явного назначения.
-
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.
-
Пользователи пользовательского типа и прокси-модели
Одно ограничение моделей пользователей пользовательского типа заключается в том, что установка модели пользователя пользовательского типа нарушит любую прокси-модель, расширяющую 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):
"""
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 get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
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 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 forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).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'
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.10/topics/auth/customizing/