Spec-Zone.ru › Django 1.8

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

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

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

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

Вы можете расширить стандартную модель User или заменить ее полностью настраиваемой моделью.

Другие источники аутентификации

Иногда требуется подключение к другому источнику аутентификации — другому источнику имен пользователей и паролей или методам аутентификации.

Например, ваша компания может уже использовать LDAP, хранящий имена пользователей и пароли каждого сотрудника. Было бы неудобно и для сетевого администратора, и для пользователей, если бы пользователи имели отдельные учетные записи в LDAP и в приложениях на базе Django.

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

См. справочник по модулям аутентификации для информации о модулях аутентификации, включённых в Django.

Указание модулей аутентификации

Внутри Django поддерживается список «модулей аутентификации», которые проверяются при аутентификации. Когда кто-то вызывает django.contrib.auth.authenticate() — как описано в Как войти в систему — Django пытается выполнить аутентификацию через все модули аутентификации. Если первый метод аутентификации не удался, Django пытается второй и так далее, пока не будут проверены все модули.

Список используемых модулей аутентификации задаётся в настройке AUTHENTICATION_BACKENDS. Это кортеж путей к 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, вы можете использовать однозначное отношение к модели, содержащей поля дополнительной информации. Эта модель с однозначным отношением часто называется моделью профиля, так как она может хранить информацию о пользователе сайта, не относящуюся к аутентификации. Например, вы можете создать модель Employee:

from django.contrib.auth.models import User

class Employee(models.Model):
    user = models.OneToOneField(User)
    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, у которых есть однозначная связь с моделью User. Поэтому они не создаются автоматически при создании пользователя, но django.db.models.signals.post_save можно использовать для создания или обновления связанных моделей, как необходимо.

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

Замена настраиваемой модели User

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

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 был изменен на другую модель User.

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)

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

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

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

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

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

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

class models.CustomUser
USERNAME_FIELD

Строка, описывающая имя поля в шаблоне пользователя, которое используется в качестве уникального идентификатора. Обычно это будет имя пользователя, но это также может быть адрес электронной почты или любой другой уникальный идентификатор. Поле обязательно должно быть уникальным (т.е., иметь unique=True в своём определении).

В следующем примере поле identifier используется в качестве идентификационного поля:

class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'

USERNAME_FIELD теперь поддерживает ForeignKey. Поскольку нет возможности передать экземпляры модели во время запроса createsuperuser, ожидайте, что пользователь введёт значение to_field (поле primary_key по умолчанию) существующего экземпляра.

REQUIRED_FIELDS

Список имён полей, которые будут запрашиваться при создании пользователя с помощью команды управления createsuperuser. Пользователю будет предложено ввести значение для каждого из этих полей. Он должен включать любое поле, для которого blank равно False или не определено, и может включать дополнительные поля, которые вы хотите запрашивать при создании пользователя интерактивно. REQUIRED_FIELDS не влияет на другие части Django, такие как создание пользователя в админке.

Например, вот частичное определение шаблона 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:

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 по умолчанию User, вы можете просто установить Django's 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
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 (строчная буква о, прописная буква о и ноль)

Расширение стандартной модели пользователя Django

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

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

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

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

  • UserCreationForm

    Зависит от модели User. Должна быть переписана для любой пользовательской модели.

  • UserChangeForm

    Зависит от модели User. Должна быть переписана для любой пользовательской модели.

  • AuthenticationForm

    Работает с любым подклассом AbstractBaseUser и адаптируется к использованию поля, определённого в USERNAME_FIELD.

  • PasswordResetForm

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

  • SetPasswordForm

    Работает с любым подклассом AbstractBaseUser

  • PasswordChangeForm

    Работает с любым подклассом AbstractBaseUser

  • AdminPasswordChangeForm

    Работает с любым подклассом AbstractBaseUser

Пользователи с пользовательскими настройками и django.contrib.admin

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

ModelBackend

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

Настраиваемые пользователи и модели-прокси

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

Spec-Zone.ru

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