Настройка аутентификации в 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() чтобы сохранить нормализацию.

classmethodget_email_field_name ()

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

classmethodnormalize_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
classmethodnormalize_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 и ноль)

Расширение User модели Django по умолчанию

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

Пользовательские пользователи и встроенные формы аутентификации

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

Следующие формы совместимы со всеми подклассами AbstractBaseUser :

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

  • 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 .

PermissionsMixin и ModelBackend

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

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

Известным ограничением настраиваемых пользовательских моделей является то, что их установка нарушает работу любых прокси-моделей, расширяющих модель 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'

Copyright ©2021 All rights reserved