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

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

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

User objects

Объекты User - основа системы аутентификации. Они представляют пользователей сайта и используются для проверки прав доступа, регистрации пользователей, ассоциации данных с пользователями. Для представления пользователей в системе аутентификации используется только один класс, таким образом 'суперпользователи' или 'персонал' - это такие же объекты пользователей, просто с определёнными атрибутами.

Основные атрибуты пользователя:

Подробности смотрите в полном описании API, текущий раздел больше ориентирован на использование аутентификации.

Создание пользователей

Самый простой способ создать пользователя – использовать метод create_user():

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')

# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()

Если вы используете интерфейс администратора Django, вы можете создать пользователя через UI.

Создание суперпользователя

Суперпользователя можно создать с помощью команды createsuperuser:

$ python manage.py createsuperuser --username=joe --email=joe@example.com

You will be prompted for a password. After you enter one, the user will be created immediately. If you leave off the --username or --email options, it will prompt you for those values.

Смена пароля

Django не хранит пароль в открытом виде, хранится только хеш (смотрите раздел о работе с паролями). Поэтому не советуем менять пароль напрямую. Именно по этой причине пользователь создается через специальную функцию.

Пароль можно сменить несколькими способами:

manage.py changepassword *username* offers a method of changing a user’s password from the command line. It prompts you to change the password of a given user which you must enter twice. If they both match, the new password will be changed immediately. If you do not supply a user, the command will attempt to change the password whose username matches the current system user.

Вы можете изменить пароль программно, используя метод set_password():

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()

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

Django также предоставляет представления и формы, которые можно использовать при создании страниц для смены пароля пользователем.

Changing a user’s password will log out all their sessions. See Сброс сессии при изменении пароля for details.

Authenticating users

authenticate(request=None, **credentials)

Use authenticate() to verify a set of credentials. It takes credentials as keyword arguments, username and password for the default case, checks them against each authentication backend, and returns a User object if the credentials are valid for a backend. If the credentials aren’t valid for any backend or if a backend raises PermissionDenied, it returns None. For example:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # A backend authenticated the credentials
else:
    # No backend authenticated the credentials

request is an optional HttpRequest which is passed on the authenticate() method of the authentication backends.

Примечание

This is a low level way to authenticate a set of credentials; for example, it’s used by the RemoteUserMiddleware. Unless you are writing your own authentication system, you probably won’t use this. Rather if you’re looking for a way to login a user, use the LoginView.

Права доступа и авторизация

Django comes with a built-in permissions system. It provides a way to assign permissions to specific users and groups of users.

Эта система используется админкой Django, но вы можете использовать её и в своем коде.

Админка использует проверку прав следующим образом:

  • Access to view objects is limited to users with the «view» or «change» permission for that type of object.
  • При доступе к странице добавления объекта проверяется наличие права «add» для объектов этого типа.
  • При доступе к страницам просмотра списка объектов и изменения объекта проверяется наличие права «change» для объектов этого типа.
  • При удалении объекта проверяется наличие права «delete» для объектов этого типа.

Permissions can be set not only per type of object, but also per specific object instance. By using the has_view_permission(), has_add_permission(), has_change_permission() and has_delete_permission() methods provided by the ModelAdmin class, it is possible to customize permissions for different object instances of the same type.

Модель User содержит связи многое ко многим с таблицами groups и user_permissions. Объект модели User работает со связанными моделями, как и другие модели Django:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

Права доступа по умолчанию

When django.contrib.auth is listed in your INSTALLED_APPS setting, it will ensure that four default permissions – add, change, delete, and view – are created for each Django model defined in one of your installed applications.

Эти права доступа создаются при выполнении команды manage.py migrate. При первом выполнении migrate, после добавления django.contrib.auth в INSTALLED_APPS, права доступа по умолчанию создаются для всех старых и новых моделей. Впоследствии команда назначает стандартные права на новые модели при каждом запуске manage.py migrate (функция, которая создаёт права, подключена к сигналу post_migrate).

Предположим у вас есть приложение с app_label foo и модель Bar. Чтобы проверить права доступа, используйте:

  • add: user.has_perm('foo.add_bar')
  • change: user.has_perm('foo.change_bar')
  • delete: user.has_perm('foo.delete_bar')
  • view: user.has_perm('foo.view_bar')

Модель Permission редко используется напрямую.

Группы

Модель django.contrib.auth.models.Group предоставляет возможность группировать пользователей, добавляя им набор прав доступа. Пользователь может принадлежать нескольким группам.

Пользователь, добавленный в группу, автоматически получает все права доступа этой группы. Например, если группа Site editors содержит права доступа can_edit_home_page, любой пользователь в этой группе получить это право доступа.

Также группы позволяют группировать пользователей, добавляя метки или дополнительные возможности. Например, вы можете создать группу 'Special users', и написать код, который предоставляет доступ к дополнительному функционалу сайта, или отправлять сообщения только пользователям этой группы.

Программное создание прав доступа

Кроме добавления своих прав доступа через класс Meta модели, вы также можете создать их напрямую. Например, создадим право доступа can_publish для модели BlogPost в приложении myapp:

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
    codename='can_publish',
    name='Can Publish Posts',
    content_type=content_type,
)

Теперь его можно добавить объекту User через атрибут user_permissions или к объекту Group через атрибут permissions.

Proxy models need their own content type

If you want to create permissions for a proxy model, pass for_concrete_model=False to ContentTypeManager.get_for_model() to get the appropriate ContentType:

content_type = ContentType.objects.get_for_model(BlogPostProxy, for_concrete_model=False)
Changed in Django 2.2:

In older versions, proxy models use the content type of the concrete model.

Кеширование прав доступа

The ModelBackend caches permissions on the user object after the first time they need to be fetched for a permissions check. This is typically fine for the request-response cycle since permissions aren’t typically checked immediately after they are added (in the admin, for example). If you are adding permissions and checking them immediately afterward, in a test or view for example, the easiest solution is to re-fetch the user from the database. For example:

from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404

from myapp.models import BlogPost

def user_gains_perms(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    # any permission check will cache the current set of permissions
    user.has_perm('myapp.change_blogpost')

    content_type = ContentType.objects.get_for_model(BlogPost)
    permission = Permission.objects.get(
        codename='change_blogpost',
        content_type=content_type,
    )
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm('myapp.change_blogpost')  # False

    # Request new instance of User
    # Be aware that user.refresh_from_db() won't clear the cache.
    user = get_object_or_404(User, pk=user_id)

    # Permission cache is repopulated from the database
    user.has_perm('myapp.change_blogpost')  # True

    ...

Proxy models

Proxy models work exactly the same way as concrete models. Permissions are created using the own content type of the proxy model. Proxy models don’t inherit the permissions of the concrete model they subclass:

class Person(models.Model):
    class Meta:
        permissions = [('can_eat_pizzas', 'Can eat pizzas')]

class Student(Person):
    class Meta:
        proxy = True
        permissions = [('can_deliver_pizzas', 'Can deliver pizzas')]

>>> # Fetch the content type for the proxy model.
>>> content_type = ContentType.objects.get_for_model(Student, for_concrete_model=False)
>>> student_permissions = Permission.objects.filter(content_type=content_type)
>>> [p.codename for p in student_permissions]
['add_student', 'change_student', 'delete_student', 'view_student',
'can_deliver_pizzas']
>>> for permission in student_permissions:
...     user.user_permissions.add(permission)
>>> user.has_perm('app.add_person')
False
>>> user.has_perm('app.can_eat_pizzas')
False
>>> user.has_perms(('app.add_student', 'app.can_deliver_pizzas'))
True
Changed in Django 2.2:

In older versions, permissions for proxy models use the content type of the concrete model rather than content type of the proxy model.

Аутентификация в запросах

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

Этот механизм предоставляет атрибут request.user для каждого запроса, который возвращает текущего пользователя. Если текущий пользователь не авторизован, атрибут содержит экземпляр AnonymousUser, иначе экземпляр User.

You can tell them apart with is_authenticated, like so:

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...

Как авторизовать пользователя

Если вы ходите привязать к сессии авторизованного пользователя, используйте функцию login().

login(request, user, backend=None)

Чтобы авторизовать пользователя в представлении, используйте функцию login(). Она принимает объект HttpRequest и объект User. Функция login() сохраняет идентификатор пользователя в сессии, используя Django приложение для работы с сессиями.

Следует отметить, что любые данные установленные в анонимной сессии будут сохранены в сессии пользователя после его авторизации.

Данные пример показывает как вы можете использовать обе функции authenticate() и login():

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.
        ...

Selecting the authentication backend

When a user logs in, the user’s ID and the backend that was used for authentication are saved in the user’s session. This allows the same authentication backend to fetch the user’s details on a future request. The authentication backend to save in the session is selected as follows:

  1. Use the value of the optional backend argument, if provided.
  2. Use the value of the user.backend attribute, if present. This allows pairing authenticate() and login(): authenticate() sets the user.backend attribute on the user object it returns.
  3. Use the backend in AUTHENTICATION_BACKENDS, if there is only one.
  4. Otherwise, raise an exception.

In cases 1 and 2, the value of the backend argument or the user.backend attribute should be a dotted import path string (like that found in AUTHENTICATION_BACKENDS), not the actual backend class.

Как отменить авторизацию пользователя

logout(request)

Для отмены авторизации пользователя, который был авторизован с помощью функции django.contrib.auth.login(), следует использовать функцию django.contrib.auth.logout() в коде вашего представления. Функция принимает объект HttpRequest и не возвращает никаких значений. Например:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

Следует отметить, что функция logout() не выбрасывает никаких ошибок, если пользователь не был ранее авторизован.

При вызове функции logout() в рамках текущего запроса будут очищены все данные сессии. Все существующие данные будут стёрты. Это происходит для того, чтобы предотвратить возможность доступа к этим данным для другого пользователя, который будет использовать тот же браузер для своей авторизации. Если потребуется поместить некие данные в сессию, которые должны быть доступны пользователя сразу после отмены его авторизации, выполняйте это после вызова функции django.contrib.auth.logout().

Ограничение доступа для неавторизованных пользователей

Прямой путь

The raw way to limit access to pages is to check request.user.is_authenticated and either redirect to a login page:

from django.conf import settings
from django.shortcuts import redirect

def my_view(request):
    if not request.user.is_authenticated:
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    # ...

… или отображение сообщения об ошибке:

from django.shortcuts import render

def my_view(request):
    if not request.user.is_authenticated:
        return render(request, 'myapp/login_error.html')
    # ...

Декоратор login_required

login_required(redirect_field_name='next', login_url=None)

Для краткости кода вы можете использовать декоратор login_required():

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

Функция login_required() делает следующее:

  • Если пользователь не авторизован, то перенаправляет его на URL, указанный в параметре конфигурации settings.LOGIN_URL, передавая текущий абсолютный путь в запросе. Например: /accounts/login/?next=/polls/3/.
  • Если пользователь авторизован, то выполняет код представления. В коде представления не требуется выполнять проверку авторизован ли пользователь или нет.

По умолчанию, в параметре "next" строки запроса хранится путь, по которому должен быть перенаправлен пользователь в результате успешной аутентификации. Если вам потребуется использовать другое имя для этого параметра, то воспользуйтесь необязательным аргументом redirect_field_name декоратора login_required():

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...

Следует отметить, что если вы воспользуетесь аргументом redirect_field_name, то вам скорее всего потребуется внести изменения в ваш шаблон авторизации, так как переменная контекста шаблона, которая содержит путь перенаправления, будет использовать значение аргумента redirect_field_name в качестве своего ключа, а не стандартное значение "next".

Декоратор login_required() также принимает необязательный аргумент login_url. Например:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

Следует отметить, что если вы не укажите аргумент login_url, то вам потребуется проверить параметр конфигурации settings.LOGIN_URL и ваше представление для авторизации соответственно настроены. Например, пользуясь стандартным поведением, добавьте следующие строки к вашей схеме URL:

from django.contrib.auth import views as auth_views

path('accounts/login/', auth_views.LoginView.as_view()),

Параметр конфигурации settings.LOGIN_URL также принимает имена представлений и именованные шаблоны URL. Это позволяет вам свободно переносить ваше представление для авторизации пользователя внутри схемы URL без необходимости изменения настроек.

Примечание

The login_required decorator does NOT check the is_active flag on a user, but the default AUTHENTICATION_BACKENDS reject inactive users.

См.также

Если вы создаёте собственные представления для интерфейса администратора (или вам нужна та же аутентификация, что используются встроенными представлениями), то вам может пригодиться декоратор django.contrib.admin.views.decorators.staff_member_required() в качестве полезной альтернативы login_required().

Примесь LoginRequired

При использовании CBV представлений, вы можете получить поведение аналогичное login_required, используя примесь LoginRequiredMixin. Эта примесь должна быть указана в самом начале списка наследования.

class LoginRequiredMixin

Если представление использует эту примесь, все запросы от неаутентифицированных пользователей будут перенаправлены на страницу аутентификации или будет показана ошибка HTTP 403 Forbidden, это зависит от параметра raise_exception.

Вы можете установить любой из параметров AccessMixin для управления обработкой неаутентифицированных пользователей:

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Примечание

Just as the login_required decorator, this mixin does NOT check the is_active flag on a user, but the default AUTHENTICATION_BACKENDS reject inactive users.

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

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

You can run your test on request.user in the view directly. For example, this view checks to make sure the user has an email in the desired domain and if not, redirects to the login page:

from django.shortcuts import redirect

def my_view(request):
    if not request.user.email.endswith('@example.com'):
        return redirect('/login/?next=%s' % request.path)
    # ...
user_passes_test(test_func, login_url=None, redirect_field_name='next')

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

from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    return user.email.endswith('@example.com')

@user_passes_test(email_check)
def my_view(request):
    ...

Декоратор user_passes_test() принимает обязательный аргумент: функцию, которая принимает объект User и возвращает True, если пользователю разрешён доступ к просмотру страницы. Следует отметить, что декоратор user_passes_test() не выполняет автоматически проверку, что User прошёл авторизацию.

Декоратор user_passes_test() принимает для необязательных аргумента:

login_url
Позволяет определеть URL на который будут перенаправляться пользователя, которые нее смогут пройти проверку. Это может быть страница авторизации или по умолчанию это будет значение параметра конфигурации settings.LOGIN_URL, если вы не указали никакого значения.
redirect_field_name
Аналогично декоратору login_required(). Присвоение значения None удаляет соответствующее поле из URL, что может вам потребоваться при перенаправлении пользователей, которые не прошли проверку, на страницу отличную от страницы авторизации.

Например:

@user_passes_test(email_check, login_url='/login/')
def my_view(request):
    ...
class UserPassesTestMixin

При использовании CBV представлений, вы можете для этой цели применять UserPassesTestMixin.

test_func()

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

from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')
get_test_func()

Вы также можете переопределить метод get_test_func(), чтобы заставить примесь использовать по-другому именованную функцию для выполнения проверки (вместо test_func()).

Цепочка из UserPassesTestMixin

Из-за особенностей реализации UserPassesTestMixin, вы не можете выстроить цепочку наследования. Следующий пример не работает:

class TestMixin1(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.email.endswith('@example.com')

class TestMixin2(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.username.startswith('django')

class MyView(TestMixin1, TestMixin2, View):
    ...

Если TestMixin1 вызовет super() и примет результат в работу, то TestMixin1 не будет больше работать в одиночку.

Декоратор permission_required

permission_required(perm, login_url=None, raise_exception=False)

Довольно частой задачей является проверка наличия определённого права у пользователя. Для решения этой задачи Django предоставляет удобный декоратор permission_required():

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
    ...

Аналогично методу has_perm(), названия прав указываются в формате "<app label>.<permission codename>" (т.е., polls.can_vote для права на модель в приложении polls).

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

Следует отметить, что декоратор permission_required() также принимает необязательный аргумент login_url:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/')
def my_view(request):
    ...

Аналогично декоратору login_required() , по умолчанию значение для аргумента login_url соответствует значению параметра конфигурации settings.LOGIN_URL.

Если определён аргумент raise_exception, то декоратор будет выбрасывать исключение PermissionDenied с описанием 403 (HTTP Forbidden) представление вместо перенаправления на страницу авторизации.

Если вам надо использовать raise_exception, но также предоставить пользователям шанс сначала аутентифицироваться, вы можете использовать декоратор login_required():

from django.contrib.auth.decorators import login_required, permission_required

@login_required
@permission_required('polls.can_vote', raise_exception=True)
def my_view(request):
    ...

This also avoids a redirect loop when LoginView’s redirect_authenticated_user=True and the logged-in user doesn’t have all of the required permissions.

Примесь PermissionRequiredMixin

Для того, чтобы выполнить проверки для CBV представлений, вы можете использовать PermissionRequiredMixin:

class PermissionRequiredMixin

This mixin, just like the permission_required decorator, checks whether the user accessing a view has all given permissions. You should specify the permission (or an iterable of permissions) using the permission_required parameter:

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'polls.can_vote'
    # Or multiple of permissions:
    permission_required = ('polls.can_open', 'polls.can_edit')

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

Вы также можете переопределить эти методы:

get_permission_required()

Возвращает перечисления имён прав, используемых примесью. По умолчанию, это содержимое атрибута permission_required, при необходимости преобразованное в кортеж.

has_permission()

Возвращает булево значение, есть ли у текущего пользователя право выполнить декорированное представление. По умолчанию, возвращается результат вызова метода has_perms() со списком прав, полученных от метода get_permission_required().

Перенаправление неаутентифицированных запросов в CBV представлениях

To ease the handling of access restrictions in class-based views, the AccessMixin can be used to configure the behavior of a view when access is denied. Authenticated users are denied access with an HTTP 403 Forbidden response. Anonymous users are redirected to the login page or shown an HTTP 403 Forbidden response, depending on the raise_exception attribute.

class AccessMixin
login_url

Стандартное значение для get_login_url(). По умолчанию, None, в этом случае метод get_login_url() возвратит settings.LOGIN_URL.

permission_denied_message

Стандартное значение для get_permission_denied_message(). По умолчанию, пустая строка.

redirect_field_name

Стандартное значение для get_redirect_field_name(). По умолчанию, "next".

raise_exception

If this attribute is set to True, a PermissionDenied exception is raised when the conditions are not met. When False (the default), anonymous users are redirected to the login page.

get_login_url()

Возвращает URL, на который будут перенаправляться пользователи не прошедшие тест. Возвращает значение атрибута login_url, если оно определено, или settings.LOGIN_URL.

get_permission_denied_message()

При raise_exception равном True, этот метод может быть использован для управления сообщением об ошибке, которое будет передано в обработчик для отображения пользователю. По умолчанию, возврашает значение атрибута permission_denied_message.

get_redirect_field_name()

Возвращает имя параметра запроса, содержащий URL, на который должен быть перенаправлен пользователь в случае успешной авторизации. Если вы установите его в None, то параметр запроса не будет добавлен. По умолчанию, возвращает значение атрибута redirect_field_name.

handle_no_permission()

В зависимости от значения raise_exception, метод либо выбрасывает исключение PermissionDenied или перенаправляет пользователя на login_url, необязательно используя redirect_field_name, если оно установлено.

Сброс сессии при изменении пароля

If your AUTH_USER_MODEL inherits from AbstractBaseUser or implements its own get_session_auth_hash() method, authenticated sessions will include the hash returned by this function. In the AbstractBaseUser case, this is an HMAC of the password field. Django verifies that the hash in the session for each request matches the one that’s computed during the request. This allows a user to log out all of their sessions by changing their password.

The default password change views included with Django, PasswordChangeView and the user_change_password view in the django.contrib.auth admin, update the session with the new password hash so that a user changing their own password won’t log themselves out. If you have a custom password change view and wish to have similar behavior, use the update_session_auth_hash() function.

update_session_auth_hash(request, user)

This function takes the current request and the updated user object from which the new session hash will be derived and updates the session hash appropriately. It also rotates the session key so that a stolen session cookie will be invalidated.

Example usage:

from django.contrib.auth import update_session_auth_hash

def password_change(request):
    if request.method == 'POST':
        form = PasswordChangeForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.user)
    else:
        ...

Примечание

Так как метод get_session_auth_hash() использует параметр конфигурации SECRET_KEY, то обновление этого параметра приведёт к отмене всех существующих сессий на сайте.

Представления аутентификации

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

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

Использование представлений

Существует несколько разных методов для реализации данных представлений в вашем проекте. Самым простым способом будет подключение схемы URL из django.contrib.auth.urls в вашу схему, например:

urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')),
]

Это действие добавить следующие шаблоны URL:

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

Представления добавляют имя для URL для упрощения ссылок на них. Обратитесь к документации на URL для получения детальной информации по использованию именованных шаблонов URL.

Если вам требуется больше контроля над вашими URL, вы можете указывать специальное представление в вашей схеме URL:

from django.contrib.auth import views as auth_views

urlpatterns = [
    path('change-password/', auth_views.PasswordChangeView.as_view()),
]

Представления принимают необязательные аргументы, которые вы можете использовать для изменения их поведения. Например, если требуется изменить имя шаблона, который будет использоваться представлением, вы можете указать аргумент template_name. Для этого надо указать именованные аргументы в схеме URL и они будут переданы в представление. Например:

urlpatterns = [
    path(
        'change-password/',
        auth_views.PasswordChangeView.as_view(template_name='change-password.html'),
    ),
]

All views are class-based, which allows you to easily customize them by subclassing.

Все представления для аутентификации

Ниже приведён список со всеми представлениями пакета django.contrib.auth. Для получения информации о деталях реализации обратитесь к Использование представлений.

class LoginView

Имя URL: login

Обратитесь к документации на URL для получения информации по использованию именованных шаблонов URL.

Attributes:

  • template_name: Путь до шаблона, который будет использовать представление при авторизации пользователя. По умолчанию, registration/login.html.

  • redirect_field_name: Имя GET поля, содержащего URL на который будет произведёно перенаправление после успешной авторизации. По умолчанию, next.

  • authentication_form: A callable (typically a form class) to use for authentication. Defaults to AuthenticationForm.

  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.

  • redirect_authenticated_user: A boolean that controls whether or not authenticated users accessing the login page will be redirected as if they had just successfully logged in. Defaults to False.

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

    If you enable redirect_authenticated_user, other websites will be able to determine if their visitors are authenticated on your site by requesting redirect URLs to image files on your website. To avoid this «social media fingerprinting» information leakage, host all images and your favicon on a separate domain.

    Enabling redirect_authenticated_user can also result in a redirect loop when using the permission_required() decorator unless the raise_exception parameter is used.

  • success_url_allowed_hosts: A set of hosts, in addition to request.get_host(), that are safe for redirecting after login. Defaults to an empty set.

Here’s what LoginView does:

  • При вызове через GET, оно отображает форму для аутентификации, которая отправляет введённые данные через POST на тот же URL. Подробности далее.
  • При вызове через POST с аутентификационными данными пользователя, оно пытается авторизовать пользователя. При успешной авторизации, представление перенаправляет на URL, указанный в next. Если параметр next не был предоставлен, происходит перенаправление на URL, содержащийся в параметре конфигурации settings.LOGIN_REDIRECT_URL (по умолчанию, /accounts/profile/). При невозможности авторизации, представление снова показывает форму.

Вашей обязанностью является предоставление HTML кода для шаблона, который по умолчанию называется registration/login.html. Данный шаблон принимает через контекст четыре переменных:

  • form: Объект Form, который представляет AuthenticationForm.
  • next: URL, на который будет осуществлено перенаправление после успешной авторизации. Можно также передавать строку запроса.
  • site: Текущий Site, соответствующий параметру конфигурации SITE_ID. Если вы не активировали соответствующее приложение, переменной будет присвоен экземпляр RequestSite, который получает имя сайта и домен из текущего HttpRequest.
  • site_name: Псевдоним для site.name. Если вы не активировали соответствующее приложение, переменной будет присвоено значение request.META['SERVER_NAME']. Для подробностей о работе с сайтами обратитесь к Фреймворк для сайтов.

If you’d prefer not to call the template registration/login.html, you can pass the template_name parameter via the extra arguments to the as_view method in your URLconf. For example, this URLconf line would use myapp/login.html instead:

path('accounts/login/', auth_views.LoginView.as_view(template_name='myapp/login.html')),

You can also specify the name of the GET field which contains the URL to redirect to after login using redirect_field_name. By default, the field is called next.

Здесь показан пример содержимого шаблона registration/login.html, который вы можете использовать в качестве отправной точки. Он предполагает, что у вас есть шаблон base.html, который определяет блок content:

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>

{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

If you have customized authentication (see Customizing Authentication) you can use a custom authentication form by setting the authentication_form attribute. This form must accept a request keyword argument in its __init__() method and provide a get_user() method which returns the authenticated user object (this method is only ever called after successful form validation).

class LogoutView

Отмена авторизации пользователя.

Имя URL: logout

Attributes:

  • next_page: The URL to redirect to after logout. Defaults to settings.LOGOUT_REDIRECT_URL.
  • template_name: The full name of a template to display after logging the user out. Defaults to registration/logged_out.html.
  • redirect_field_name: Имя GET поля, содержащего URL на который будет произведёно перенаправление после отмены авторизации. По умолчанию, next. Переопределяет next_page, если данный параметр был передан в GET.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.
  • success_url_allowed_hosts: A set of hosts, in addition to request.get_host(), that are safe for redirecting after logout. Defaults to an empty set.

Контекст шаблона:

  • title: Локализованная строка «Logged out».
  • site: Текущий Site, соответствующий параметру конфигурации SITE_ID. Если вы не активировали соответствующее приложение, переменной будет присвоен экземпляр RequestSite, который получает имя сайта и домен из текущего HttpRequest.
  • site_name: Псевдоним для site.name. Если вы не активировали соответствующее приложение, переменной будет присвоено значение request.META['SERVER_NAME']. Для подробностей о работе с сайтами обратитесь к Фреймворк для сайтов.
logout_then_login(request, login_url=None)

Отменяет авторизацию пользователя, затем перенаправляет на страницу авторизации.

Имя URL: Значения по умолчанию нет

Необязательные аргументы:

  • login_url: URL страницы авторизации, на которую будет выполнено перенаправление. По умолчанию, settings.LOGIN_URL.
class PasswordChangeView

Имя URL: password_change

Позволяет пользователю изменить его пароль.

Attributes:

  • template_name: Путь до шаблона, который будет использовать представление при изменении пароля. По умолчанию, registration/password_change_form.html.
  • success_url: The URL to redirect to after a successful password change.
  • form_class: A custom «change password» form which must accept a user keyword argument. The form is responsible for actually changing the user’s password. Defaults to PasswordChangeForm.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.

Контекст шаблона:

  • form: The password change form (see form_class above).
class PasswordChangeDoneView

Имя URL: password_change_done

Страница, отображаемая после того, как пользователь изменил свой пароль.

Attributes:

  • template_name: Путь до шаблона. По умолчанию, registration/password_change_done.html.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.
class PasswordResetView

Имя URL: password_reset

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

If the email address provided does not exist in the system, this view won’t send an email, but the user won’t receive any error message either. This prevents information leaking to potential attackers. If you want to provide an error message in this case, you can subclass PasswordResetForm and use the form_class attribute.

Пользователь, отмеченный флагом отменённого пароля (см. set_unusable_password()), не может запросить сброс пароля. Так сделано, чтобы предотвратить неправильное использование при работе с внешними источниками аутентификации, например, с LDAP. Следует отметить, что они не получат никаких сообщений об ошибках, так как это вскрыло бы наличие аккаунта, и никакого сообщения на почту не будет отправлено.

Attributes:

  • template_name: Путь до шаблона, который будет использоваться для отображения формы сброса пароля. По умолчанию, registration/password_reset_form.html.
  • form_class: Form that will be used to get the email of the user to reset the password for. Defaults to PasswordResetForm.
  • email_template_name: Путь до шаблона, который используется при генерации сообщения со ссылкой для сброса пароля, отправляемого на адрес электронной почты. По умолчанию, registration/password_reset_email.html.
  • subject_template_name: Путь до шаблона, который используется при генерации заголовка сообщения со ссылкой для сброса пароля, отправляемого на адрес электронной почты. По умолчанию registration/password_reset_subject.txt.
  • token_generator: Экземпляр класса для проверки одноразовой ссылки. По умолчанию, default_token_generator, который является экземпляром django.contrib.auth.tokens.PasswordResetTokenGenerator.
  • success_url: The URL to redirect to after a successful password reset request.
  • from_email: Корректный адрес электронной почты. По умолчанию Django использует DEFAULT_FROM_EMAIL.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.
  • html_email_template_name: Путь до шаблона, который будет использоваться при генерации text/html блока электронного сообщения с ссылкой для сброса пароля. По умолчанию, сообщение в формате HTML не отправляется.
  • extra_email_context: A dictionary of context data that will be available in the email template. It can be used to override default template context values listed below e.g. domain.

Контекст шаблона:

  • form: The form (see form_class above) for resetting the user’s password.

Контекст шаблона электронной почты:

  • email: Псевдоним для user.email
  • user: Текущий User, соответствующий полю email формы. Толька активные пользователи имеют возможность сбрасывать свои пароли passwords (User.is_active is True).
  • site_name: Псевдоним для site.name. Если вы не активировали соответствующее приложение, переменной будет присвоено значение request.META['SERVER_NAME']. Для подробностей о работе с сайтами обратитесь к Фреймворк для сайтов.
  • domain: Псевдоним для site.domain. Если вы не используете приложение для работы с сайтами, то значением будет request.get_host().
  • protocol: http или https
  • uid: Первичный ключ пользователя, закодированный в base 64.
  • token: Токен для проверки корректности ссылки для сброса пароля.

Пример registration/password_reset_email.html (шаблон тела письма):

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

Такой же контекст используется для шаблона заголовка сообщения. Заголовок должен быть представлен одной строкой простого текста.

class PasswordResetDoneView

Имя URL: password_reset_done

The page shown after a user has been emailed a link to reset their password. This view is called by default if the PasswordResetView doesn’t have an explicit success_url URL set.

Примечание

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

Attributes:

  • template_name: Путь до шаблона. По умолчанию, registration/password_reset_done.html.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.
class PasswordResetConfirmView

Имя URL: password_reset_confirm

Представляет форму для ввода нового пароля.

Keyword arguments from the URL:

  • uidb64: The user’s id encoded in base 64.
  • token: Token to check that the password is valid.

Attributes:

  • template_name: Путь до шаблона, который использует представление для подтверждения пароля. По умолчанию, registration/password_reset_confirm.html.

  • token_generator: Эеземпляр класса для проверки пароля. По умолчанию, default_token_generator, это экземпляр django.contrib.auth.tokens.PasswordResetTokenGenerator.

  • post_reset_login: A boolean indicating if the user should be automatically authenticated after a successful password reset. Defaults to False.

  • post_reset_login_backend: A dotted path to the authentication backend to use when authenticating a user if post_reset_login is True. Required only if you have multiple AUTHENTICATION_BACKENDS configured. Defaults to None.

  • form_class: Form that will be used to set the password. Defaults to SetPasswordForm.

  • success_url: URL to redirect after the password reset done. Defaults to 'password_reset_complete'.

  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.

  • reset_url_token: Token parameter displayed as a component of password reset URLs. Defaults to 'set-password'.

    Changed in Django 3.0:

    The reset_url_token class attribute was added.

Контекст шаблона:

  • form: The form (see form_class above) for setting the new user’s password.
  • validlink: Булево значение. True, если ссылка (комбинация uidb64 и token) корректна и не была ещё использована.
class PasswordResetCompleteView

Имя URL: password_reset_complete

Представление, которое информирует пользователя об успешном изменении пароля.

Attributes:

  • template_name: Путь до шаблона. По умолчанию, registration/password_reset_complete.html.
  • extra_context: Словарь с контекстными данными, которые будут добавлены в текущий контекст, перед его передачей в шаблон.

Вспомогательные функции

redirect_to_login(next, login_url=None, redirect_field_name='next')

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

Обязательные аргументы:

  • next: URL на который происходит перенаправление после успешной авторизации.

Необязательные аргументы:

  • login_url: URL страницы авторизации, на которую будет выполнено перенаправление. По умолчанию, settings.LOGIN_URL.
  • redirect_field_name: Имя GET поля, содержащего URL на который будет произведёно перенаправление после отмены авторизации. Переопределяет next. если данный параметр был передан в GET.

Встроенные формы

Если вы не желаете использовать встроенные представления, но и формы переписывать не хотите, то система аутентификации предоставляет несколько встроенных форм, расположенных в django.contrib.auth.forms:

Примечание

The built-in authentication forms make certain assumptions about the user model that they are working with. If you’re using a custom user model, it may be necessary to define your own forms for the authentication system. For more information, refer to the documentation about using the built-in authentication forms with custom user models.

class AdminPasswordChangeForm

Форма, используемая в интерфейса администратора, для изменения пароля пользователя.

Принимает user в качестве первого неименованного параметра.

class AuthenticationForm

Форма для аутентификации пользователя.

Принимает request в качестве первого неименованного аргумента, который сохраняется в экземпляре формы для использования подклассами.

confirm_login_allowed(user)

По умолчанию, форма AuthenticationForm игнорирует пользователей у которых флаг is_active установлен в False. Вы можете изменить это поведение на проверку некого права пройти аутентификацию для пользователей. Выполните это с помощью своей формы, которая унаследована от AuthenticationForm и переопределяет метод confirm_login_allowed(). Этот метод должен выбрасывать исключение ValidationError в случае, если указанный пользователь не может проходить аутентификацию.

Например, позволяем всем пользователям проходить аутентификацию, невзирая на их статус активности:

from django.contrib.auth.forms import AuthenticationForm

class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
    def confirm_login_allowed(self, user):
        pass

(In this case, you’ll also need to use an authentication backend that allows inactive users, such as AllowAllUsersModelBackend.)

Или позволяем только некоторым активным пользователям проходить аутентификацию:

class PickyAuthenticationForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not user.is_active:
            raise forms.ValidationError(
                _("This account is inactive."),
                code='inactive',
            )
        if user.username.startswith('b'):
            raise forms.ValidationError(
                _("Sorry, accounts starting with 'b' aren't welcome here."),
                code='no_b_users',
            )
class PasswordChangeForm

Форма, через которую пользователь может менять свой пароль.

class PasswordResetForm

Форма для генерации и отправки одноразовой ссылки для сброса пользовательского пароля.

send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)

Использует аргументы для отправки EmailMultiAlternatives. Может быть переопределена для изменения способа отправки сообщения пользователю.

Параметры:
  • subject_template_name – шаблон для заголовка.
  • email_template_name – шаблон для тела письма.
  • context – контекст передаётся в subject_template, email_template и html_email_template (если он не None).
  • from_email – адрес электронной почты отправителя.
  • to_email – адрес электронной почты пользователя.
  • html_email_template_name – шаблон для HTML тела письма, по умолчанию, None, в этом случае отсылается обычный текст.

By default, save() populates the context with the same variables that PasswordResetView passes to its email context.

class SetPasswordForm

Форма, которая позволяет пользователю изменять свой пароль без ввода старого пароля.

class UserChangeForm

Форма, используемая в интерфейсе администратора для изменения информации о пользователе и его списка прав.

class UserCreationForm

A ModelForm for creating a new user.

It has three fields: username (from the user model), password1, and password2. It verifies that password1 and password2 match, validates the password using validate_password(), and sets the user’s password using set_password().

Аутентификационные данные в шаблонах

Авторизованный пользователь и его права доступны в шаблонном контексте при использовании RequestContext.

Техническая особенность

Технически, эти переменные становятся доступными в шаблонном контексте, только если вы используете RequestContext и активирован контекстный процессор 'django.contrib.auth.context_processors.auth'. По умолчанию проект так и настроен. Больше информации можно найти в документации на RequestContext.

Пользователи

При рендеринге RequestContext, авторизованный пользователь, неважно будет это экземпляр User или AnonymousUser, сохраняется в шаблонной переменной {{ user }}:

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
    <p>Welcome, new user. Please log in.</p>
{% endif %}

Эта шаблонная переменная не доступна, если не используется RequestContext.

Права

Права авторизованного пользователя хранятся в шаблонной переменной {{ perms }}. Она связана с экземпляром django.contrib.auth.context_processors.PermWrapper, который реализует доступ к правам.

Evaluating a single-attribute lookup of {{ perms }} as a boolean is a proxy to User.has_module_perms(). For example, to check if the logged-in user has any permissions in the foo app:

{% if perms.foo %}

Evaluating a two-level-attribute lookup as a boolean is a proxy to User.has_perm(). For example, to check if the logged-in user has the permission foo.can_vote:

{% if perms.foo.can_vote %}

Here’s a more complete example of checking permissions in a template:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.can_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.can_drive %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

Также позможен поиск прав с помощью выражения {% if in %}. Например:

{% if 'foo' in perms %}
    {% if 'foo.can_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}

Управление пользователями в интерфейсе администратора

Если вы подключили к проекту django.contrib.admin и django.contrib.auth, интерфейс администратора предоставляет удобный способ для просмотра и управления пользователями, группами и правами. Пользователи могут быть созданы и удалены как любая другая модель Django. Группы могут быть созданы и права могут быть назначены на пользователей и группы. Журнал изменений, выполненных через интерфейс администратора, сохраняется и доступен.

Создание пользователей

Вы должны видеть сылку на «Пользователи» в разделе «Auth» на главной странице интерфейса администратора. Страница «Добавить пользователя» отличается от других страниц интерфейса, так как она требует, чтобы вы ввели имя пользователя и пароль перед тем как дать вам возможность редактировать остальные поля модели.

Также следует отметить, что если вам нужен пользоватедль, который бы позволил создавать пользователей с помощью интерфейса администратора, вам следует дать ему право на добавление пользователей и право на изменение пользователей (т.е., права «Добавить пользователя» и «Изменить пользователя»). Если пользователь обладает правом создания пользователей, но не имеет права на их редактирование, тогда он не сможет создавать пользователей. Почему? Потому что, если у вас есть право на создание пользователей, у вас есть возможность создать суперпользователей, которые могут в свою очередь, изменять других пользователей. Таким образом, Django требует наличие прав на добавление и изменение пользователей в целях безопасности.

Продумайте как вы позволяете управлять правами. Если вы предоставите обычному пользователю право на редактирование пользователей, это будет означать то же самое, что и предоставление ему прав суперпользователя, так как он сможет повысить права пользователей, включая себя!

Смена пароля

Пароли пользователей не отображаются на интерфейсе администратора (и не сохраняются в базе данных), но отображаются детали хранилища пароля. Рядом с этой информацией находится ссылка на форму изменения пароля, которая позволяет администраторам изменять пароли пользователей.