Использование системы аутентификации Django
В этом документе описывается использование системы аутентификации Django в её стандартной конфигурации. Эта конфигурация разработана для удовлетворения наиболее распространённых потребностей проектов, обрабатывая широкий спектр задач, и имеет продуманную реализацию паролей и разрешений. Для проектов, где потребности в аутентификации отличаются от стандартных, Django поддерживает расширенную настройку и расширение системы аутентификации.
Система аутентификации Django обеспечивает как аутентификацию, так и авторизацию, и обычно называется системой аутентификации, так как эти функции несколько взаимосвязаны.
User объекты
User объекты являются основой системы аутентификации. Они обычно представляют людей, взаимодействующих с вашим сайтом, и используются для таких задач, как ограничение доступа, регистрация профилей пользователей, привязка контента к создателям и т. д. В рамках фреймворка аутентификации Django существует только один класс пользователей, т. е. 'superusers' или администраторские '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 admin, вы также можете создавать пользователей интерактивно.
Создание суперпользователей
Создайте суперпользователей с помощью команды createsuperuser:
$ python manage.py createsuperuser --username=joe --email=joe@example.com
Вам будет предложено ввести пароль. После ввода пароль будет сразу же сохранён. Если вы опустите опции --username или --email, вам будет предложено ввести эти значения.
Изменение паролей
Django не хранит исходные (текстовые) пароли в модели пользователя, а только хэш (см. документацию по управлению паролями для получения подробной информации). Из-за этого не пытайтесь напрямую изменять атрибут пароля пользователя. Именно поэтому для создания пользователя используется вспомогательная функция.
Для изменения пароля пользователя у вас есть несколько вариантов:
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 admin, вы также можете изменить пароли пользователей на страницах администратора системы аутентификации.
Django также предоставляет представления и формы, которые могут быть использованы для разрешения пользователям изменения собственных паролей.
Изменение пароля пользователя приведёт к выходу из всех их сессий. Подробности см. в разделе Недействительность сессии при смене пароля.
Аутентификация пользователей
-
authenticate(request=None, **credentials) -
Используйте
authenticate()для проверки набора учетных данных. Он принимает учетные данные в качестве ключевых аргументов,usernameиpasswordв стандартном случае, проверяет их по каждому аутентификационному бэкенду и возвращает объект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 credentialsrequest— это необязательныйHttpRequest, который передаётся в методauthenticate()аутентификационных бэкендов.Примечание
Это низкоуровневый способ аутентификации набора учетных данных; например, он используется
RemoteUserMiddleware. Если вы не пишете собственную систему аутентификации, вы, скорее всего, не будете использовать её. Вместо этого, если вы ищете способ входа пользователя, используйтеLoginView.
Разрешения и авторизация
Она используется в админ-панели Django, но вы можете использовать её и в своём коде.
Админ-панель Django использует разрешения следующим образом:
- Доступ к просмотру объектов ограничен для пользователей с разрешением «просмотр» или «изменение» для этого типа объекта.
- Доступ к форме «добавления» и добавлению объекта ограничен для пользователей с разрешением «добавление» для этого типа объекта.
- Доступ к просмотру списка изменений, просмотру формы «изменение» и изменению объекта ограничен для пользователей с разрешением «изменение» для этого типа объекта.
- Доступ к удалению объекта ограничен для пользователей с разрешением «удаление» для этого типа объекта.
Разрешения могут быть установлены не только для типа объекта, но и для конкретного экземпляра объекта. Используя методы has_view_permission(), has_add_permission(), has_change_permission() и has_delete_permission(), предоставляемые классом ModelAdmin, можно настраивать разрешения для различных экземпляров объектов одного типа.
User объекты имеют два поля many-to-many: 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()
Стандартные разрешения
Когда 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', и вы могли бы написать код, который, скажем, предоставил бы им доступ к закрытой для членов части вашего сайта или отправлял им закрытые для членов электронные сообщения.
Программное создание разрешений
Хотя настраиваемые разрешения могут быть определены внутри класса 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.
Моделям-прокси требуется собственный тип контента
Если вы хотите создать разрешения для модели-прокси, передайте 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
Авторизация в веб-запросах
Django использует сессии и промежуточное ПО для подключения системы аутентификации к 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. ...
Выбор бэкенда аутентификации
Когда пользователь входит в систему, идентификатор пользователя и бэкенд, который использовался для аутентификации, сохраняются в сессии пользователя. Это позволяет одному и тому же бэкенду аутентификации извлекать данные пользователя в последующем запросе. Бэкенд аутентификации для сохранения в сессии выбирается следующим образом:
- Используйте значение необязательного аргумента
backendпри его наличии. - Используйте значение атрибута
user.backend, если он присутствует. Это позволяет связатьauthenticate()иlogin():authenticate()устанавливает атрибутuser.backendв объекте пользователя, который он возвращает. - Используйте значение
backendвAUTHENTICATION_BACKENDS, если оно единственное. - В противном случае вызовите исключение.
В случаях 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()не генерирует никаких ошибок, если пользователь не был авторизован.Когда вы вызываете
logout(), данные сессии для текущего запроса полностью очищаются. Все существующие данные удаляются. Это для предотвращения использования одним человеком одного веб-браузера для входа в систему и доступа к данным сессии предыдущего пользователя. Если вы хотите поместить что-либо в сессию, что будет доступно пользователю сразу после выхода из системы, сделайте это *после* вызова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('%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()выполняет следующие действия:- Если пользователь не авторизован, перенаправляет его на
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также принимает имена функций представления и имена шаблонов URL. Это позволяет вам свободно переназначать ваше представление входа в файле URLconf без необходимости обновления настроек. - Если пользователь не авторизован, перенаправляет его на
Примечание
Декоратор login_required НЕ проверяет флаг is_active пользователя, но по умолчанию AUTHENTICATION_BACKENDS отклоняет неактивных пользователей.
См. также
Если вы пишете пользовательские представления для администрирования Django (или вам нужна та же проверка авторизации, что и в встроенных представлениях), вы можете найти декоратор django.contrib.admin.views.decorators.staff_member_required() полезной альтернативой декоратору login_required().
Миксин LoginRequired
При работе с представлениями на основе классов, можно добиться такого же поведения, как и с 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 непосредственно в представлении. Например, это представление проверяет, имеет ли пользователь электронную почту в нужном домене, и если нет, перенаправляет его на страницу входа:
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 -
При работе с представлениями на основе классов, вы можете использовать
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, вызывая отображение страницы 403 (HTTP Forbidden) вместо перенаправления на страницу входа.Если вы хотите использовать
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’sredirect_authenticated_user=Trueи авторизованный пользователь не обладает всеми необходимыми правами.
Mixin PermissionRequiredMixin
Для применения проверок разрешений к представлениям на основе классов, вы можете использовать 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 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) -
Эта функция принимает текущий запрос и обновлённый объект пользователя, на основе которого будет вычислен новый хэш сессии, и соответственно обновляет хэш сессии. Она также меняет ключ сессии, чтобы украденный куки сессии стал недействительным.
Пример использования:
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 не предоставляет по умолчанию шаблон для представлений аутентификации. Вы должны создать свои собственные шаблоны для нужных вам представлений. Контекст шаблона описан в каждом представлении, см. Все представления аутентификации.
Использование представлений
Существуют разные способы реализации этих представлений в вашем проекте. Самый простой способ — включить предоставленный 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 см. в документации по URL.
Если вам требуется больший контроль над вашими 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'),
),
]
Все представления основаны на классах, что позволяет легко настраивать их путём наследования.
Все представления аутентификации
Это список всех представлений, которые django.contrib.auth предоставляет. Подробности реализации см. в Разделе "Использование представлений".
-
class LoginView -
Имя URL:
loginПодробную информацию об использовании именованных шаблонов URL см. в документации по URL.
Атрибуты:
-
template_name: Имя шаблона, отображаемого для представления, используемого для входа пользователя. По умолчаниюregistration/login.html. -
redirect_field_name: Имя поляGETсодержащего URL для перенаправления после входа. По умолчаниюnext. -
authentication_form: Вызываемый объект (обычно класс формы) для использования в аутентификации. По умолчаниюAuthenticationForm. -
extra_context: Словарь данных контекста, который будет добавлен к стандартным данным контекста, передаваемым шаблону. -
redirect_authenticated_user: Булевое значение, управляющее перенаправлением авторизованных пользователей, обращающихся к странице входа, как если бы они только что успешно вошли. По умолчаниюFalse.Предупреждение
Если вы включите
redirect_authenticated_user, другие веб-сайты смогут определить, авторизованы ли их посетители на вашем сайте, запросив URL перенаправления к файлам изображений на вашем сайте. Чтобы избежать утечки информации «отслеживание в социальных сетях», размещайте все изображения и значок закладки на отдельном домене.Включение
redirect_authenticated_userтакже может привести к циклу перенаправления при использовании декоратораpermission_required(), если не используется параметрraise_exception. -
success_url_allowed_hosts:setхостов, помимоrequest.get_host(), которые безопасны для перенаправления после входа. По умолчанию пустойset.
Вот что делает
LoginView:- Если вызвана через
GET, она отображает форму входа, которая отправляет POST-запрос на тот же 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']. Дополнительную информацию о сайтах см. в фреймворке "sites".
Если вы предпочитаете не вызывать шаблон
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 setup the password_reset view in your URLconf #} <p><a href="{% url 'password_reset' %}">Lost password?</a></p> {% endblock %}Если вы настроили аутентификацию (см. Настройка аутентификации), вы можете использовать пользовательскую форму аутентификации, задав атрибут
authentication_form. Эта форма должна принимать аргументrequestв методе__init__()и предоставлять методget_user(), который возвращает аутентифицированный объект пользователя (этот метод вызывается только после успешной валидации формы). -
-
class LogoutView -
Выводит пользователя из системы.
Имя URL:
logoutАтрибуты:
-
next_page: URL перенаправления после выхода. По умолчаниюsettings.LOGOUT_REDIRECT_URL. -
template_name: Полное имя шаблона для отображения после выхода из системы. По умолчаниюregistration/logged_out.html. -
redirect_field_name: Имя поляGETсодержащего URL перенаправления после выхода. По умолчаниюnext_pageURL, если передан параметрGET. -
extra_context: Словарь данных контекста, которые будут добавлены к стандартным данным контекста, передаваемым шаблону. -
success_url_allowed_hosts:setхостов, помимоrequest.get_host(), которые безопасны для перенаправления после выхода. По умолчанию пустойset.
Контекст шаблона:
-
title: Строка “Выход”, локализованная. -
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Разрешает пользователю изменить свой пароль.
Атрибуты:
-
template_name: Полное имя шаблона для отображения формы смены пароля. По умолчаниюregistration/password_change_form.html. -
success_url: URL перенаправления после успешной смены пароля. По умолчанию'password_change_done'. -
form_class: Кастомная форма "смены пароля", которая должна принимать ключевой аргументuser. Форма отвечает за фактическое изменение пароля пользователя. По умолчаниюPasswordChangeForm. -
extra_context: Словарь данных контекста, которые будут добавлены к стандартным данным контекста, передаваемым шаблону.
Контекст шаблона:
-
form: Форма смены пароля (см.form_classвыше).
-
-
class PasswordChangeDoneView -
Имя URL:
password_change_doneСтраница, отображаемая после смены пароля пользователем.
Атрибуты:
-
template_name: Полное имя шаблона для использования. По умолчаниюregistration/password_change_done.html. -
extra_context: Словарь данных контекста, которые будут добавлены к стандартным данным контекста, передаваемым шаблону.
-
-
class PasswordResetView -
Имя URL:
password_resetПозволяет пользователю сбросить пароль, сгенерировав одноразовую ссылку, которую можно использовать для сброса пароля и отправив эту ссылку на зарегистрированный электронный адрес пользователя.
Если электронный адрес, указанный пользователем, отсутствует в системе, этот вид не отправит письмо, но пользователь также не получит сообщение об ошибке. Это предотвращает утечку информации потенциальным злоумышленникам. Если вы хотите отобразить сообщение об ошибке в этом случае, вы можете создать подкласс
PasswordResetFormи использовать атрибутform_class.Примечание
Обратите внимание, что отправка электронного письма требует дополнительного времени, поэтому вы можете быть уязвимы к атаке на перечисление адресов электронной почты из-за разницы во времени между запросом на сброс для существующего адреса электронной почты и запросом на сброс для несуществующего адреса электронной почты. Чтобы уменьшить нагрузку, вы можете использовать сторонний пакет, который позволяет асинхронно отправлять письма, например, django-mailer.
Пользователи, отмеченные как имеющие неиспользуемый пароль (см.
set_unusable_password()), не могут запросить сброс пароля, чтобы предотвратить злоупотребления при использовании внешнего источника аутентификации, например, LDAP. Обратите внимание, что они не получат никакого сообщения об ошибке, так как это раскрыло бы существование их учетной записи, но письмо также не будет отправлено.Атрибуты:
-
template_name: Полное имя шаблона для отображения формы сброса пароля. По умолчаниюregistration/password_reset_form.html. -
form_class: Форма, которая будет использоваться для получения адреса электронной почты пользователя для сброса пароля. По умолчанию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: URL перенаправления после успешного запроса на сброс пароля. По умолчанию'password_reset_done'. -
from_email: Действительный адрес электронной почты. По умолчанию Django используетDEFAULT_FROM_EMAIL. -
extra_context: Словарь данных контекста, которые будут добавлены к стандартным данным контекста, передаваемым шаблону. -
html_email_template_name: Полное имя шаблона для создания text/html многочастичного письма со ссылкой на сброс пароля. По умолчанию HTML-письма не отправляются. -
extra_email_context: Словарь данных контекста, которые будут доступны в шаблоне письма. Он может быть использован для переопределения стандартных значений контекста шаблона, например,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нет явногоsuccess_urlURL.Примечание
Если указанный адрес электронной почты не существует в системе, пользователь неактивен или имеет непригодный пароль, пользователь по-прежнему будет перенаправлен на этот вид, но письмо не будет отправлено.
Атрибуты:
-
template_name: Полное имя шаблона для использования. По умолчаниюregistration/password_reset_done.htmlесли не указано. -
extra_context: Словарь данных контекста, которые будут добавлены к данным контекста по умолчанию, передаваемым шаблону.
-
-
class PasswordResetConfirmView -
Имя URL:
password_reset_confirmОтображает форму для ввода нового пароля.
Ключевые аргументы из URL:
-
uidb64: Идентификатор пользователя, закодированный в base 64. -
token: Токен для проверки того, что пароль действителен.
Атрибуты:
-
template_name: Полное имя шаблона для отображения подтверждения пароля. Значение по умолчаниюregistration/password_reset_confirm.html. -
token_generator: Экземпляр класса для проверки пароля. По умолчаниюdefault_token_generator, это экземплярdjango.contrib.auth.tokens.PasswordResetTokenGenerator. -
post_reset_login: Логическое значение, указывающее, должен ли пользователь быть автоматически аутентифицирован после успешного сброса пароля. По умолчаниюFalse. -
post_reset_login_backend: Точка доступа к аутентификационному бэкенду, который нужно использовать при аутентификации пользователя, еслиpost_reset_loginравноTrue. Требуется только если у вас настроено несколькоAUTHENTICATION_BACKENDS. По умолчаниюNone. -
form_class: Форма, которая будет использоваться для установки пароля. По умолчаниюSetPasswordForm. -
success_url: URL для перенаправления после завершения сброса пароля. По умолчанию'password_reset_complete'. -
extra_context: Словарь данных контекста, которые будут добавлены к данным контекста по умолчанию, передаваемым шаблону. -
reset_url_token: Параметр токена, отображаемый как часть URL-адресов сброса пароля. По умолчанию'set-password'.
Контекст шаблона:
-
form: Форма (см.form_classвыше) для установки нового пароля пользователя. -
validlink: Логическое значение, True, если ссылка (сочетаниеuidb64иtoken) действительна или ещё не использовалась.
-
-
class PasswordResetCompleteView -
Имя URL:
password_reset_completeОтображает вид, информирующий пользователя о том, что пароль был успешно изменён.
Атрибуты:
-
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:
Примечание
Встроенные формы аутентификации делают определённые предположения о модели пользователя, с которой они работают. Если вы используете пользовательскую модель, может потребоваться определить собственные формы для системы аутентификации. Для получения дополнительной информации обратитесь к документации по использованию встроенных форм аутентификации с пользовательскими моделями.
-
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 -
ModelFormдля создания нового пользователя.У неё есть три поля:
username(из модели пользователя),password1иpassword2. Она проверяет, чтоpassword1иpassword2совпадают, валидирует пароль с помощьюvalidate_password()и устанавливает пароль пользователя с помощью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, который представляет собой дружественный шаблону прокси разрешений.
Оценивание одноатрибутного поиска {{ 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, вам нужно предоставить им разрешение на добавление пользователей и изменение пользователей (т.е. разрешения «Добавить пользователя» и «Изменить пользователя»). Если учетная запись имеет разрешение на добавление пользователей, но не на их изменение, эта учетная запись не сможет добавлять пользователей. Почему? Потому что, если у вас есть разрешение на добавление пользователей, вы можете создавать суперпользователей, которые, в свою очередь, могут изменять других пользователей. Поэтому Django требует разрешений на добавление и изменение как дополнительную меру безопасности.
Внимательно подходите к тому, как вы позволяете пользователям управлять разрешениями. Если вы предоставляете не-суперпользователю возможность редактировать пользователей, это в конечном счете равносильно предоставлению ему статуса суперпользователя, так как он сможет повышать разрешения пользователей, включая себя!
Изменение паролей
Пароли пользователей не отображаются в админпанели (и не хранятся в базе данных), но отображаются подробности хранения паролей. В этом отображении информации также есть ссылка на форму изменения пароля, которая позволяет администраторам изменять пароли пользователей.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/topics/auth/default/