Spec-Zone.ru › Django 1.9

Настройка аутентификации в Django

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

Модули аутентификации обеспечивают расширяемую систему, когда имя пользователя и пароль, хранящиеся в модели User, должны быть аутентифицированы с помощью другого сервиса, отличного от стандартного 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 — это может быть имя пользователя, идентификатор базы данных или что-то другое, но должно быть первичным ключом вашего объекта User — и возвращает объект User.

Метод 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 должен проверить предоставленные данные аутентификации и, если они действительны, вернуть объект User , соответствующий этим данным. Если данные неверны, он должен вернуть 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. Note that we can set password
                # to anything, because it won't be checked; the password
                # from settings.py will.
                user = User(username=username, password='get from settings.py')
                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):
        if user_obj.username == settings.ADMIN_LOGIN:
            return True
        else:
            return False

Это предоставляет полные разрешения пользователю, получившему доступ в вышеприведённом примере. Обратите внимание, что помимо тех же аргументов, что и у соответствующих функций django.contrib.auth.models.User, все функции аутентификации модуля принимают объект пользователя, который может быть анонимным пользователем, в качестве аргумента.

Полную реализацию авторизации можно найти в классе ModelBackend в django/contrib/auth/backends.py, который является стандартным модулем и в большинстве случаев обращается к таблице auth_permission. Если вы хотите предоставить пользовательское поведение только для части API модуля, вы можете воспользоваться наследованием Python и вместо этого унаследовать класс ModelBackend , вместо реализации всего API в пользовательском модуле.

Авторизация для анонимных пользователей

Анонимный пользователь — это пользователь, который не авторизован, т. е. он не предоставил действительных данных аутентификации. Однако это не обязательно означает, что он не имеет права на что-либо. На самом базовом уровне большинство веб-сайтов разрешают анонимным пользователям просматривать большую часть сайта, и многие разрешают анонимную публикацию комментариев и т. д.

В рамках системы разрешений Django нет места для хранения разрешений для анонимных пользователей. Однако объект пользователя, передаваемый модулю аутентификации, может быть объектом django.contrib.auth.models.AnonymousUser, что позволяет модулю задать пользовательское поведение авторизации для анонимных пользователей. Это особенно полезно для авторов повторно используемых приложений, которые могут делегировать все вопросы авторизации модулю аутентификации, а не, например, нуждаться в настройках для управления доступом анонимных пользователей.

Авторизация для неактивных пользователей

Неактивный пользователь — это пользователь, который прошёл аутентификацию, но у которого атрибут is_active установлен в False. Однако это не означает, что у него нет права на что-либо. Например, ему разрешено активировать свою учётную запись.

Поддержка анонимных пользователей в системе разрешений позволяет сценарий, где анонимные пользователи имеют разрешения на выполнение определённых действий, в то время как неактивные аутентифицированные пользователи этого не имеют.

Не забудьте проверить атрибут is_active пользователя в собственных методах разрешений своего модуля.

Обработка разрешений на объекты

В рамках системы разрешений 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)

Предполагая, что существует существующий 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, которые имеют связь один-к-одному с моделью User. Поэтому они не создаются автоматически при создании пользователя, но django.db.models.signals.post_save может быть использован для создания или обновления связанных моделей по мере необходимости.

Обратите внимание, что использование связанных моделей приводит к дополнительным запросам или объединениям для извлечения связанных данных, и в зависимости от ваших потребностей замена модели User и добавление связанных полей может быть лучшим вариантом. Однако существующие ссылки на стандартную модель User в приложениях вашего проекта могут оправдывать дополнительные нагрузки на базу данных.

Замена пользовательской User модели

В некоторых типах проектов требования к аутентификации могут быть таковы, что встроенная в Django модель User не всегда подходит. Например, на некоторых сайтах для идентификатора более подходит использование адреса электронной почты вместо имени пользователя.

Django позволяет вам переопределить стандартную модель User, задав значение параметра AUTH_USER_MODEL, которое ссылается на пользовательскую модель:

AUTH_USER_MODEL = 'myapp.MyUser'

Эта пара с точками описывает имя приложения Django (которое должно быть в вашем INSTALLED_APPS), и имя модели Django, которую вы хотите использовать в качестве модели User.

Предупреждение

Изменение AUTH_USER_MODEL оказывает большое влияние на структуру вашей базы данных. Оно изменяет доступные таблицы и повлияет на построение внешних ключей и взаимосвязей многие-ко-многим. Если вы намерены установить AUTH_USER_MODEL, вы должны установить его до создания каких-либо миграций или выполнения manage.py migrate в первый раз.

Изменение этого параметра после создания таблиц не поддерживается makemigrations и приведёт к необходимости ручного исправления схемы, переноса данных из старой таблицы пользователей и, возможно, ручного повторного применения некоторых миграций.

Предупреждение

Из-за ограничений динамической функции зависимости Django для взаимозаменяемых моделей необходимо убедиться, что модель, на которую ссылается AUTH_USER_MODEL, создана в первой миграции её приложения (обычно называется 0001_initial); в противном случае возникнут проблемы с зависимостями.

Кроме того, при выполнении миграций может возникнуть ошибка CircularDependencyError, так как Django не сможет автоматически разорвать петлю зависимости из-за динамической зависимости. Если вы видите эту ошибку, вы должны разорвать петлю, переместив модели, от которых зависит ваша модель User, во вторую миграцию (вы можете попробовать создать две обычные модели, у которых есть 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 — настраиваемую модель User, если она указана, или User в противном случае.

При определении внешних ключей или отношений многие-ко-многим к модели 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,
    )

При подключении к сигналам, отправляемым моделью User, вы должны указать пользовательскую модель, используя параметр 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)

В общем случае, вы должны ссылаться на модель User с помощью AUTH_USER_MODEL в коде, который выполняется во время импорта. get_user_model() работает только после того, как Django импортировал все модели.

Определение пользовательской User модели

Рекомендации по проектированию моделей

Внимательно обдумайте, как обрабатывать информацию, не напрямую связанную с аутентификацией, в вашей пользовательской модели.

Может быть лучше хранить информацию о пользователе, специфичную для приложения, в модели, имеющей отношение к модели User. Это позволяет каждому приложению указать свои собственные требования к данным пользователя, не рискуя конфликтами с другими приложениями. С другой стороны, запросы на извлечение этой связанной информации потребуют объединения в базе данных, что может повлиять на производительность.

Django ожидает, что ваша пользовательская модель User будет соответствовать минимальным требованиям.

  1. Если вы используете стандартный модуль аутентификации, ваша модель должна иметь одно уникальное поле, которое можно использовать для идентификации. Это может быть имя пользователя, адрес электронной почты или любой другой уникальный атрибут. Поле имени пользователя, не являющееся уникальным, разрешено, если вы используете пользовательский модуль аутентификации, который может его поддерживать.
  2. Ваша модель должна предоставить способ обращения к пользователю в «короткой» и «длинной» форме. Наиболее распространённым способом было бы использовать имя пользователя в качестве «короткого» идентификатора и полное имя пользователя в качестве «длинного» идентификатора. Однако нет ограничений на то, что возвращают эти два метода — если хотите, они могут возвращать точно одно и то же значение.

В более старых версиях Django ваша модель также должна была иметь целочисленный первичный ключ.

Самый простой способ создать совместимую пользовательскую модель пользователя — унаследовать от AbstractBaseUser. AbstractBaseUser предоставляет основную реализацию модели User, включая хэшированные пароли и токенизированные сбросы паролей. Затем вам необходимо указать некоторые ключевые детали реализации:

class models.CustomUser
USERNAME_FIELD

Строка, описывающая имя поля в модели User, которое используется в качестве уникального идентификатора. Обычно это имя пользователя, но также может быть адрес электронной почты или любой другой уникальный идентификатор. Поле должно быть уникальным (т. е., иметь 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, например, при создании пользователя в админке.

Например, вот частичное определение модели User, которая определяет два обязательных поля — дату рождения и рост:

class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ['date_of_birth', 'height']

Примечание

REQUIRED_FIELDS должен содержать все необходимые поля в вашей модели User, но не должен содержать 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

AbstractBaseUser и BaseUserManager импортируются из django.contrib.auth.base_user, чтобы их можно было импортировать без включения django.contrib.auth в INSTALLED_APPS (в более ранних версиях это вызывало предупреждение о устаревании и больше не поддерживается в Django 1.9).

Следующие методы доступны для любого подкласса AbstractBaseUser:

class models.AbstractBaseUser
get_username()

Возвращает значение поля, указанного в USERNAME_FIELD.

is_anonymous()

Всегда возвращает False. Это способ различения объектов AnonymousUser. В целом, следует отдавать предпочтение использованию is_authenticated() вместо этого метода.

is_authenticated()

Всегда возвращает True. Это способ узнать, был ли пользователь аутентифицирован. Это не подразумевает никаких разрешений и не проверяет, активен ли пользователь — это только указывает, что пользователь предоставил действительное имя пользователя и пароль.

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 поля пароля. Используется для Отмены сеанса при смене пароля.

Также необходимо определить пользовательский менеджер для вашей User модели. Если ваша User модель определяет поля username, email, is_staff, is_active, is_superuser, last_login, и date_joined таким же образом, как и по умолчанию в Django, вы можете просто установить менеджер Django UserManager; однако, если ваша User модель определяет другие поля, вам потребуется определить пользовательский менеджер, который расширяет 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 и ноль)

Расширение стандартной User Django

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

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

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

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

  • AuthenticationForm: Использует поле имени пользователя, заданное USERNAME_FIELD.
  • SetPasswordForm
  • PasswordChangeForm
  • AdminPasswordChangeForm

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

  • PasswordResetForm: Предполагает, что модель пользователя имеет поле с именем email, которое может использоваться для идентификации пользователя, и булевое поле с именем is_active, чтобы предотвратить сброс пароля для неактивных пользователей.

И, наконец, следующие формы привязаны к User и должны быть переписаны или расширены для работы с пользовательской моделью:

  • UserCreationForm
  • UserChangeForm

Если ваша пользовательская модель является простым подклассом 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.

PermissionsMixin и ModelBackend

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

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

Одним из ограничений пользовательских моделей является то, что установка кастомной модели пользователя нарушит любую прокси-модель, расширяющую User. Прокси-модели должны базироваться на конкретном базовом классе; определяя кастомную модель пользователя, вы лишаете Django возможности надёжной идентификации базового класса.

Если ваш проект использует прокси-модели, вы должны либо изменить прокси для расширения модели пользователя, которая сейчас используется в вашем проекте, либо объединить поведение прокси в свой подкласс модели пользователя.

Полный пример

Вот пример админ-совместимой кастомной модели пользователя. Эта модель пользователя использует адрес электронной почты в качестве имени пользователя и требует дату рождения; она не предоставляет проверки разрешений, кроме простого флага 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.9/topics/auth/customizing/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API