Настройка аутентификации в 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 — который может быть именем пользователя, идентификатором базы данных или чем-то ещё, но должен быть первичным ключом вашего объекта пользователя — и возвращает объект пользователя.
Метод authenticate принимает аргумент request и данные для проверки в качестве ключевых аргументов. В большинстве случаев он будет выглядеть так:
class MyBackend(object):
def authenticate(self, request, username=None, password=None):
# Check the username/password and return a user.
...
Но он также может аутентифицировать токен, как в этом случае:
class MyBackend(object):
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.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, 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
Параметр request был добавлен в authenticate() и поддержка модулей, которые не принимают его, будет удалена в Django 2.1.
Обработка авторизации в пользовательских модулях
Модель пользователя делегирует функции поиска разрешений (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 разрешал аутентификацию неактивных пользователей.
Обработка разрешений на объекты
Система разрешений Django имеет основу для разрешений на объекты, хотя в ядре нет реализации. Это означает, что проверка разрешений на объекты всегда вернёт False или пустой список (в зависимости от выполняемой проверки). Модуль аутентификации получит ключевые параметры obj и user_obj для каждого метода авторизации, связанного с объектом, и может вернуть разрешения на уровень объекта соответствующим образом.
Пользовательские разрешения
Чтобы создать пользовательские разрешения для заданного объекта модели, используйте атрибут 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')
Расширение существующей 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)
Предполагая, что существует существующий сотрудник Fred Smith, у которого есть как модель 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()[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, поэтому вы можете использовать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 1.11:Была добавлена возможность вызова
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'USERNAME_FIELDтеперь поддерживаетForeignKey. Поскольку нет способа передать экземпляры модели во время запросаcreatesuperuser, ожидается, что пользователь введёт значениеto_field(по умолчанию полеprimary_key) существующего экземпляра.
-
EMAIL_FIELD -
Новое в Django 1.11.
Строка, описывающая имя поля электронной почты в модели
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, так как эти поля всегда будут запрошены.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().
Импорт
AbstractBaseUserAbstractBaseUserиBaseUserManagerимпортируемы изdjango.contrib.auth.base_user, чтобы их можно было импортировать, не включаяdjango.contrib.authвINSTALLED_APPS. -
Следующие атрибуты и методы доступны для любого подкласса AbstractBaseUser:
-
class models.AbstractBaseUser -
-
get_username() -
Возвращает значение поля, указанного в
USERNAME_FIELD.
-
clean() -
Новое в Django 1.10.
Нормализует имя пользователя, вызывая
normalize_username(). Если вы переопределяете этот метод, убедитесь, что вызываетеsuper()для сохранения нормализации.
-
classmethod get_email_field_name() -
Новое в Django 1.11.
Возвращает имя поля электронной почты, указанное в атрибуте
EMAIL_FIELD. По умолчанию'email'еслиEMAIL_FIELDне указано.
-
classmethod normalize_username(username) -
Новое в Django 1.10.
Применяет Unicode-нормализацию NFKC к именам пользователей, чтобы визуально идентичные символы с разными кодами Unicode считались идентичными.
-
is_authenticated -
Только для чтения атрибут, который всегда
True(в отличие отAnonymousUser.is_authenticated, который всегдаFalse). Это способ определить, был ли пользователь аутентифицирован. Это не подразумевает никаких разрешений и не проверяет, активен ли пользователь или имеет ли он действительную сессию. Хотя обычно вы будете проверять этот атрибут дляrequest.userчтобы узнать, был ли он заполненAuthenticationMiddleware(представляющий текущего вошедшего пользователя), вы должны знать, что этот атрибут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 поля пароля. Используется для Отмены сеанса при изменении пароля.
-
AbstractUser наследуется от AbstractBaseUser:
-
class models.AbstractUser -
-
clean() -
Новое в Django 1.11.
Нормализует электронную почту, вызывая
BaseUserManager.normalize_email(). Если вы переопределяете этот метод, убедитесь, что вызываетеsuper()для сохранения нормализации.
-
Вам также следует определить пользовательский менеджер для вашей модели пользователя. Если ваша модель пользователя определяет поля 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: Предполагает, что модель пользователя имеет поле, хранящее адрес электронной почты пользователя с именем, возвращаемым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, которых нет в вашем пользовательском классе.
Пользователи и разрешения
Для удобства включения фреймворка разрешений 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.11/topics/auth/customizing/