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

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

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

User объекты

Объекты User являются ядром системы аутентификации. Они обычно представляют людей, взаимодействующих с вашим сайтом, и используются для таких вещей, как ограничение доступа, регистрация профилей пользователей, ассоциирование контента с создателями и т.д. В системе аутентификации Django существует только один класс пользователей, т.е. пользователи 'superusers' или admin 'staff' - это просто объекты пользователей с установленными специальными атрибутами, а не разные классы объектов пользователей.

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

См. full API documentation для полной справки, следующая документация больше ориентирована на задачи.

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

Самый прямой способ создания пользователей - использовать включенную вспомогательную функцию 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, вы также можете create users interactively.

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

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

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

Вам будет предложено ввести пароль. После ввода пароля пользователь будет создан немедленно. Если вы не указали параметры --username или --email, будет предложено ввести эти значения.

Изменение паролей

Django не хранит необработанные (открытый текст) пароли в модели пользователя, а только хэш (см. documentation of how passwords are managed для полной информации). В связи с этим не пытайтесь манипулировать атрибутом password пользователя напрямую. Поэтому при создании пользователя используется вспомогательная функция.

Чтобы изменить пароль пользователя, у вас есть несколько вариантов:

manage.py changepassword *username* предлагает метод изменения пароля пользователя из командной строки. Он предлагает вам изменить пароль данного пользователя, который вы должны ввести дважды. Если они оба совпадают, то новый пароль будет немедленно изменен. Если вы не укажете пользователя, команда попытается изменить пароль пользователя, чье имя пользователя совпадает с именем текущего пользователя системы.

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

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

Если у вас установлен админ Django, вы также можете изменить пароли пользователей на странице authentication system’s admin pages.

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

Изменение пароля пользователя приведет к выходу из всех его сессий. Подробнее см. в разделе Аннулирование сессии при смене пароля.

Аутентификация пользователей

authenticate(request=None, **credentials)[исходный код]

Используйте authenticate() для проверки набора учетных данных. Она принимает учетные данные в качестве аргументов ключевых слов, username и password для случая по умолчанию, сверяет их с каждым authentication backend и возвращает объект User, если учетные данные действительны для бэкенда. Если учетные данные не действительны ни для одного бэкенда или если бэкенд поднимает PermissionDenied, возвращается None. Например:

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 - необязательный HttpRequest, который передается в методе authenticate() бэкендов аутентификации.

Примечание

Это низкоуровневый способ аутентификации набора учетных данных; например, его использует RemoteUserMiddleware. Если вы не пишете свою собственную систему аутентификации, вы, вероятно, не будете ее использовать. Скорее, если вы ищете способ входа пользователя в систему, используйте LoginView.

Разрешения и авторизация

Django поставляется со встроенной системой разрешений. Она позволяет назначать разрешения конкретным пользователям и группам пользователей.

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

Административный сайт Django использует разрешения следующим образом:

  • Доступ к объектам просмотра ограничен пользователями, имеющими разрешение «просмотр» или «изменение» для данного типа объекта.
  • Доступ к просмотру формы «Добавить» и добавлению объекта ограничен пользователями с правом «Добавить» для данного типа объекта.
  • Доступ к просмотру списка изменений, форме «изменения» и изменению объекта ограничен пользователями с правом «изменения» для данного типа объекта.
  • Доступ к удалению объекта ограничен пользователями, имеющими разрешение «удалить» для данного типа объекта.

Разрешения могут быть установлены не только для типа объекта, но и для конкретного экземпляра объекта. Используя методы has_view_permission(), has_add_permission(), has_change_permission() и has_delete_permission(), предоставляемые классом ModelAdmin, можно настроить разрешения для различных экземпляров объектов одного типа.

Объекты User имеют два поля типа «многие-ко-многим»: groups и user_permissions. Объекты User могут обращаться к связанным с ними объектам так же, как и к любым другим Django model:

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()

Разрешения по умолчанию

Когда django.contrib.auth указано в настройках INSTALLED_APPS, это гарантирует, что четыре разрешения по умолчанию - добавление, изменение, удаление и просмотр - будут созданы для каждой модели Django, определенной в одном из ваших установленных приложений.

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

Предположим, что у вас есть приложение с app_label foo и моделью с именем Bar, для проверки основных разрешений вы должны использовать:

  • добавить: user.has_perm('foo.add_bar')
  • изменение: user.has_perm('foo.change_bar')
  • удалить: user.has_perm('foo.delete_bar')
  • вид: user.has_perm('foo.view_bar')

К модели Permission редко обращаются напрямую.

Групи

django.contrib.auth.models.Group Модели - это общий способ категоризации пользователей, чтобы вы могли применять к ним разрешения или другие метки. Пользователь может принадлежать к любому количеству групп.

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

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

Программное создание разрешений

Хотя custom permissions может быть определено в классе 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.

Прокси-модели нуждаются в собственном типе содержимого

Если вы хотите создать permissions for a proxy model, передайте for_concrete_model=False в ContentTypeManager.get_for_model(), чтобы получить соответствующее ContentType:

content_type = ContentType.objects.get_for_model(BlogPostProxy, for_concrete_model=False)

Кэширование разрешений

ModelBackend кэширует разрешения на объект пользователя после первого раза, когда они должны быть получены для проверки разрешений. Обычно это подходит для цикла запрос-ответ, поскольку разрешения обычно не проверяются сразу после их добавления (например, в админке). Если вы добавляете разрешения и проверяете их сразу после этого, например, в тесте или представлении, самым простым решением будет повторная выборка пользователя из базы данных. Например:

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

    ...

Модели прокси

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

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

Authentication in web requests

Django использует sessions и промежуточное ПО для подключения системы аутентификации к request objects.

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

Вы можете различать их с помощью is_authenticated, например, так:

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

Выбор бэкенда аутентификации

Когда пользователь входит в систему, его ID и бэкенд, который использовался для аутентификации, сохраняются в сессии пользователя. Это позволяет тому же authentication backend получить данные пользователя при последующем запросе. Бэкэнд аутентификации для сохранения в сессии выбирается следующим образом:

  1. Используйте значение необязательного аргумента backend, если он предоставлен.
  2. Используйте значение атрибута user.backend, если он присутствует. Это позволяет использовать пары authenticate() и login(): authenticate() устанавливает атрибут user.backend на возвращаемом объекте пользователя.
  3. Используйте backend в AUTHENTICATION_BACKENDS, если есть только один.
  4. В противном случае вызовите исключение.

В случаях 1 и 2 значением аргумента backend или атрибута user.backend должна быть строка пути импорта с точкой (как в AUTHENTICATION_BACKENDS), а не реальный класс бэкенда.

Как выйти из системы

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() не выдает никаких ошибок, если пользователь не вошел в систему.

When you call logout(), the session data for the current request is completely cleaned out. All existing data is removed. This is to prevent another person from using the same web browser to log in and have access to the previous user’s session data. If you want to put anything into the session that will be available to the user immediately after logging out, do that after calling django.contrib.auth.logout().

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

Сырой способ

Необработанный способ ограничения доступа к страницам - это проверка request.user.is_authenticated и либо перенаправление на страницу входа:

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

def my_view(request):
    if not request.user.is_authenticated:
        return redirect(f'{settings.LOGIN_URL}?next={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() делает следующее:

  • Если пользователь не вошел в систему, перенаправьте его на settings.LOGIN_URL, передав текущий абсолютный путь в строке запроса. Пример: /accounts/login/?next=/polls/3/.
  • Если пользователь вошел в систему, выполните представление нормально. Код представления может считать, что пользователь вошел в систему.

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

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

from django.contrib.auth import views as auth_views

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

settings.LOGIN_URL также принимает имена функций представления и named URL patterns. Это позволяет вам свободно переназначать представление входа в URLconf без необходимости обновлять настройки.

Примечание

Декоратор login_required НЕ проверяет флаг is_active у пользователя, но по умолчанию AUTHENTICATION_BACKENDS отвергает неактивных пользователей.

См.также

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

The LoginRequiredMixin mixin

При использовании class-based views можно добиться того же поведения, что и при 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'

Примечание

Как и декоратор login_required, этот миксин НЕ проверяет флаг is_active на пользователе, но по умолчанию AUTHENTICATION_BACKENDS отклоняет неактивных пользователей.

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

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

Вы можете запустить свой тест на request.user в представлении напрямую. Например, это представление проверяет, есть ли у пользователя email в нужном домене, и если нет, перенаправляет на страницу входа:

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

При использовании class-based views, вы можете использовать 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.add_choice')
def my_view(request):
    ...

Как и в методе has_perm(), имена разрешений принимают форму "<app label>.<permission codename>" (например, polls.add_choice для разрешения на модель в приложении polls).

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

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

from django.contrib.auth.decorators import permission_required

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

Как и в декораторе login_required(), login_url по умолчанию равен settings.LOGIN_URL.

Если задан параметр raise_exception, декоратор поднимет PermissionDenied, предлагая the 403 (HTTP Forbidden) view вместо перенаправления на страницу входа.

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

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

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

Это также позволяет избежать цикла перенаправления, когда LoginView становится redirect_authenticated_user=True, а у вошедшего пользователя нет всех необходимых прав.

Миксин PermissionRequiredMixin

Чтобы применить проверку разрешений к class-based views, вы можете использовать PermissionRequiredMixin:

class PermissionRequiredMixin

Этот миксин, как и декоратор permission_required, проверяет, имеет ли пользователь, обращающийся к представлению, все заданные разрешения. Вы должны указать разрешение (или итерацию разрешений) с помощью параметра permission_required:

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'polls.add_choice'
    # Or multiple of permissions:
    permission_required = ['polls.view_choice', 'polls.change_choice']

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

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

get_permission_required()

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

has_permission()

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

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

Чтобы облегчить обработку ограничений доступа в class-based views, AccessMixin можно использовать для настройки поведения представления при отказе в доступе. Аутентифицированным пользователям отказывается в доступе с ответом HTTP 403 Forbidden. Анонимные пользователи перенаправляются на страницу входа или показывают ответ HTTP 403 Forbidden, в зависимости от атрибута raise_exception.

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

Если этот атрибут установлен в True, то при невыполнении условий возникает исключение PermissionDenied. Если False (по умолчанию), анонимные пользователи перенаправляются на страницу входа в систему.

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, если оно установлено.

Аннулирование сессии при смене пароля

Если ваш AUTH_USER_MODEL наследует от AbstractBaseUser или реализует свой собственный метод get_session_auth_hash(), аутентифицированные сессии будут включать хэш, возвращаемый этой функцией. В случае AbstractBaseUser это HMAC поля пароля. Django проверяет, что хэш в сессии для каждого запроса совпадает с тем, который вычисляется во время запроса. Это позволяет пользователю выйти из всех своих сессий, изменив пароль.

Представления смены пароля по умолчанию, входящие в Django, PasswordChangeView и представление user_change_password в админке django.contrib.auth, обновляют сессию новым хэшем пароля, чтобы пользователь, меняющий свой пароль, не вышел из системы. Если у вас есть пользовательское представление смены пароля и вы хотите иметь подобное поведение, используйте функцию update_session_auth_hash().

update_session_auth_hash(request, user)[исходный код]

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

Пример использования:

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

Примечание

Since get_session_auth_hash() is based on SECRET_KEY, secret key values must be rotated to avoid invalidating existing sessions when updating your site to use a new secret. See SECRET_KEY_FALLBACKS for details.

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

Django предоставляет несколько представлений, которые вы можете использовать для обработки входа, выхода и управления паролями. В них используется stock auth forms, но вы можете передавать и свои собственные формы.

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

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

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

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 см. в the URL documentation.

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

from django.contrib.auth import views as auth_views

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

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

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

Все представления являются class-based, что позволяет легко настраивать их с помощью подклассов.

Все виды аутентификации

Это список со всеми представлениями, которые предоставляет django.contrib.auth. Подробности реализации смотрите в Использование представлений.

class LoginView

Имя URL: login

Подробнее об использовании именованных шаблонов URL см. в разделе the URL documentation.

Methods and Attributes

template_name

The name of a template to display for the view used to log the user in. Defaults to registration/login.html.

next_page

The URL to redirect to after login. Defaults to LOGIN_REDIRECT_URL.

redirect_field_name

The name of a GET field containing the URL to redirect to after login. Defaults to next. Overrides the get_default_redirect_url() URL if the given GET parameter is passed.

authentication_form

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

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

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.

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

Если вы включите опцию redirect_authenticated_user, другие сайты смогут определить, авторизованы ли их посетители на вашем сайте, запрашивая URL перенаправления на файлы изображений на вашем сайте. Чтобы избежать такой утечки информации social media fingerprinting», размещайте все изображения и ваш favicon на отдельном домене.

Включение redirect_authenticated_user также может привести к циклу перенаправления при использовании декоратора permission_required(), если не используется параметр raise_exception.

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.

get_default_redirect_url()

Returns the URL to redirect to after login. The default implementation resolves and returns next_page if set, or LOGIN_REDIRECT_URL otherwise.

Вот что делает LoginView:

  • При вызове через GET отображается форма входа в систему, которая POSTs на тот же URL. Подробнее об этом чуть позже.
  • При вызове через POST с учетными данными, предоставленными пользователем, он пытается войти в систему. В случае успешного входа представление перенаправляется на URL, указанный в next. Если next не указан, он перенаправляется на 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']. Подробнее о сайтах смотрите Структура «сайтов».

Если вы предпочитаете не вызывать шаблон registration/login.html, вы можете передать параметр template_name через дополнительные аргументы методу as_view в вашем URLconf. Например, эта строка URLconf будет использовать myapp/login.html вместо:

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

Вы также можете указать имя поля GET, которое содержит URL-адрес для перенаправления на него после входа в систему с помощью redirect_field_name. По умолчанию поле называется 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 set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

Если вы настроили аутентификацию (см. Customizing Authentication), вы можете использовать пользовательскую форму аутентификации, установив атрибут authentication_form. Эта форма должна принимать аргумент с ключевым словом request в своем методе __init__() и предоставлять метод get_user(), который возвращает объект аутентифицированного пользователя (этот метод вызывается только после успешной проверки формы).

class LogoutView

Logs a user out on POST requests.

Не рекомендуется, начиная с версии 4.1: Поддержка выхода из системы при запросах GET устарела и будет удалена в Django 5.0.

Имя URL: logout

Атрибуты:

next_page

The URL to redirect to after logout. Defaults to 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

The name of a GET field containing the URL to redirect to after log out. Defaults to 'next'. Overrides the next_page URL if the given GET parameter is passed.

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

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)

Logs a user out on POST requests, then redirects to the login page.

Имя URL: URL по умолчанию не предоставляется

Дополнительные аргументы:

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

Не рекомендуется, начиная с версии 4.1: Поддержка выхода из системы при запросах GET устарела и будет удалена в Django 5.0.

class PasswordChangeView

Имя URL: password_change

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

Атрибуты:

template_name

The full name of a template to use for displaying the password change form. Defaults to registration/password_change_form.html if not supplied.

success_url

The URL to redirect to after a successful password change. Defaults to 'password_change_done'.

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

A dictionary of context data that will be added to the default context data passed to the template.

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

  • form: Форма смены пароля (см. form_class выше).
class PasswordChangeDoneView

Имя URL: password_change_done

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

Атрибуты:

template_name

The full name of a template to use. Defaults to registration/password_change_done.html if not supplied.

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

class PasswordResetView

Имя URL: password_reset

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

Это представление будет отправлять сообщение электронной почты, если выполняются следующие условия:

  • Указанный адрес электронной почты существует в системе.
  • Запрашиваемый пользователь активен (User.is_active равно True).
  • The requested user has a usable password. Users flagged with an unusable password (see set_unusable_password()) aren’t allowed to request a password reset to prevent misuse when using an external authentication source like LDAP.

If any of these conditions are not met, no email will be sent, 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.

Примечание

Имейте в виду, что отправка электронного письма требует дополнительного времени, поэтому вы можете быть уязвимы для атаки перечисления адресов электронной почты по времени из-за разницы между длительностью запроса сброса для существующего адреса электронной почты и длительностью запроса сброса для несуществующего адреса электронной почты. Чтобы уменьшить накладные расходы, можно использовать сторонний пакет, позволяющий отправлять электронные письма асинхронно, например, django-mailer.

Атрибуты:

template_name

The full name of a template to use for displaying the password reset form. Defaults to registration/password_reset_form.html if not supplied.

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

The full name of a template to use for generating the email with the reset password link. Defaults to registration/password_reset_email.html if not supplied.

subject_template_name

The full name of a template to use for the subject of the email with the reset password link. Defaults to registration/password_reset_subject.txt if not supplied.

token_generator

Instance of the class to check the one time link. This will default to default_token_generator, it’s an instance of django.contrib.auth.tokens.PasswordResetTokenGenerator.

success_url

The URL to redirect to after a successful password reset request. Defaults to 'password_reset_done'.

from_email

A valid email address. By default Django uses the DEFAULT_FROM_EMAIL.

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

html_email_template_name

The full name of a template to use for generating a text/html multipart email with the password reset link. By default, HTML email is not sent.

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: Форма (см. form_class выше) для сброса пароля пользователя.

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

  • email: Псевдоним для user.email
  • user: Текущий User, в соответствии с полем формы email. Только активные пользователи могут сбрасывать свои пароли (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

Страница, отображаемая после того, как пользователь получил по электронной почте ссылку для сброса пароля. Это представление вызывается по умолчанию, если для PasswordResetView не задан явный URL success_url.

Примечание

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

Атрибуты:

template_name

The full name of a template to use. Defaults to registration/password_reset_done.html if not supplied.

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

class PasswordResetConfirmView

Имя URL: password_reset_confirm

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

Ключевые аргументы из URL:.

  • uidb64: Идентификатор пользователя, закодированный в base 64.
  • token: Токен для проверки правильности пароля.

Атрибуты:

template_name

The full name of a template to display the confirm password view. Default value is registration/password_reset_confirm.html.

token_generator

Instance of the class to check the password. This will default to default_token_generator, it’s an instance of 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

A dictionary of context data that will be added to the default context data passed to the template.

reset_url_token

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

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

  • form: Форма (см. form_class выше) для установки пароля нового пользователя.
  • validlink: Булево, истинно, если ссылка (комбинация uidb64 и token) действительна или еще не использована.
class PasswordResetCompleteView

Имя URL: password_reset_complete

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

Атрибуты:

template_name

The full name of a template to display the view. Defaults to registration/password_reset_complete.html.

extra_context

A dictionary of context data that will be added to the default context data passed to the template.

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

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:

Примечание

Встроенные формы аутентификации делают определенные предположения о модели пользователя, с которой они работают. Если вы используете custom user model, может потребоваться определить собственные формы для системы аутентификации. Для получения дополнительной информации обратитесь к документации по 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

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

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

class PickyAuthenticationForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not user.is_active:
            raise ValidationError(
                _("This account is inactive."),
                code='inactive',
            )
        if user.username.startswith('b'):
            raise 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, в этом случае отправляется обычное текстовое письмо.

По умолчанию save() заполняет context теми же переменными, которые PasswordResetView передает своему почтовому контексту.

class SetPasswordForm

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

class UserChangeForm

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

class UserCreationForm

A ModelForm для создания нового пользователя.

Он имеет три поля: username (из модели пользователя), password1 и password2. Он проверяет соответствие password1 и password2, проверяет пароль с помощью validate_password() и устанавливает пароль пользователя с помощью set_password().

Changed in Django 4.2:

В старых версиях UserCreationForm не сохранял поля формы «многие ко многим» для пользовательской модели пользователя.

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

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

Техничность

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

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

При отображении шаблона 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, который является дружественным шаблону прокси разрешения.

Оценка одноатрибутного поиска {{ perms }} как булева является прокси для User.has_module_perms(). Например, чтобы проверить, есть ли у вошедшего пользователя какие-либо разрешения в приложении foo:

{% if perms.foo %}

Оценка двухуровневого атрибута поиска как булева является прокси для User.has_perm(). Например, чтобы проверить, есть ли у вошедшего пользователя разрешение foo.add_vote:

{% if perms.foo.add_vote %}

Вот более полный пример проверки разрешений в шаблоне:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.add_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.add_driving %}
        <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.add_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}

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

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

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

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

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

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

Изменение паролей

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

Вернуться на верх