本文档介绍了 Django 验证系统在默认配置下的使用方法。默认配置满足最常见的项目需求,可以处理相当多的任务,还有一个安全的密码和权限实现。对于验证需求与默认配置不同的项目,Django 支持对身份验证进行扩展和定制。
Django 验证同时提供身份验证和授权,通常称为身份验证系统,因为这些功能在某种程度上是耦合的。
User
对象¶用户对象是认证系统的核心。它通常代表了与你的站点交互的人员,并用于允许诸如限制访问、注册用户配置文件、将内容与创建者关联等功能。Django 的认证框架中用户只有一个类,例如 “超级管理员”或“普通管理员”只是具有特殊属性集的用户对象,而不是用户对象的不同类。
默认用户的主要属性是:
请参阅完整的API文档 full API documentation
以获得完整的参考,下面的文档主要以任务为导向。
The most direct way to create users is to use the included
create_user()
helper function:
>>> 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 管理后台,你也可以在 admin 管理后台交互式地创建用户:ref:create users interactively <auth-admin> 。
Create superusers using the createsuperuser
command:
$ python manage.py createsuperuser --username=joe --email=joe@example.com
...\> py manage.py createsuperuser --username=joe --email=joe@example.com
你将会被提示输入密码,完成之后,超级管理员就被创建成功了。如果你没有填写参数 --username <createsuperuser --username> ` or :option:
--email <createsuperuser --email>` ,也将会被提示输入这些值。
Django 不会在用户模型里保存原始(明文)密码,而只会存储哈希值(请参阅文档 如何管理密码 documentation of how passwords are managed ) 。因此,请不要试图直接操作用户的密码,这就是创建用户需要辅助函数的原因。
更改一个用户的密码,你有几个选择:
manage.py changepassword *username*
提供了在命令行修改用户密码的方法。它会提示你输入两次新密码,如果操作成功,新密码就立刻生效。如果你没有提供参数 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 管理后台,你也可以在管理后台页面修改密码(请参阅 :ref:`authentication system's admin pages ` )。
Django 还提供了允许用户自行修改密码的 :ref:`views ` 和 :ref:`forms ` 。
修改密码将会注销用户的所有会话。查看详情请参阅 密码更改时会话失效 。
authenticate
(request=None, **credentials)¶使用 authenticate()
来验证用户。它使用 username
和 password
作为参数来验证,对每个身份验证后端( authentication backend ` )进行检查。如果后端验证有效,则返回一个 :class:`~django.contrib.auth.models.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 的 admin 页面使用了如下权限:
不仅可以为每个对象类型设置权限,还可以为每个指定对象实例设置权限。通过使用 ModelAdmin
类提供的 has_view_permission()
, has_add_permission()
, has_change_permission()
和 has_delete_permission()
方法,可以为同一类型的不同实例定制权限。
User
对象有两个多对多字段:groups
和 user_permissions
。 User
对象可以像访问其他 :doc:`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()
当 INSTALLED_APPS
设置了 django.contrib.auth
时,它将确保你的每个 Django 模型被创建时有四个默认权限:添加、修改、删除和查看。
运行 manage.py migrate
时将创建这些权限。当你添加 django.contrib.auth
到 INSTALLED_APPS
后第一次运行 迁移
,将会为所有只去已经安装过的模型以及现在正在安装的模型创建这些默认的权限。之后,每次你运行 manage.py migrate
都会为新模型创建默认权限 (创建权限的函数连接 post_migrate
信号)。
假设你有一个名为 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')
权限模型很少会被直接访问。
django.contrib.auth.models.Group
模型是对用户进行分类的通用方法,因此您可以将权限或其他标签应用于这些用户。用户可以属于任意数量的组。
组里的用户会自动拥有该组的权限。举例,如果 Site editors
组有修改网站首页的权限,那么该组的任何成员都有这个权限。
除权限外,组是一个方便的途径,可以给用户分类,为其提供一些标签或扩展功能。例如,你可以创建一个组 'Special users'
,并在编写的代码里让该组成员访问网站仅限会员部分的内容,或者对该组成员发送仅限会员查看的电子邮件。
虽然可以在模型的 Meta
类中定义 custom permissions ,你也可以直接创建权限。例如,你可以为 BlogPost
模型创建 can_publish
权限。
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_permissions
属性将权限分配给 User
,或通过 permissions
属性分配给 Group
。
代理模型需要自己的内容类型
如果你想创建 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
才会缓存它们的权限。对于请求-响应周期来说,这通常是很好的,因为权限通常不会在添加的时候立刻检查(例如,在 admin 中)。如果你打算在测试或视图中添加权限,并随后检查他们,最简单的解决方案就是从数据库中重新获取用户。例如:
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 使用 sessions 和中间件将身份验证系统挂接到请求对象中。
它们在每次请求中都会提供 request.user
属性。如果当前没有用户登录,这个属性将会被设置为 AnonymousUser
,否则将会被设置为 User
实例。
你可以使用 is_authenticated
区分两者,例如:
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
如果有一个已验证的用户想附加到当前会话(session)中,将通过 login()
函数完成。
login
(request, user, backend=None)¶要在视图中让用户登录,使用 login()
。它需要 HttpRequest
对象和 User
对象。通过 Django 的 session 框架, login()
会在 session 中保存用户的ID。
注意,在匿名会话期间设置的任何数据都会在用户登录后保留在会话中。
这个例子展示了如何使用 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 在未来的请求中获取用户详情。选择要在会话中保存的验证后端如下:
backend
参数值。user.backend
的值。允许配对 authenticate()
和 login()
:当返回用户对象时 authenticate()
设置 user.backend
属性。AUTHENTICATION_BACKENDS
存在的 backend
。在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
和登录视图是正确关联的。例如,使用默认方式,在 URL 配置文件里添加下面这行:
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()
的一个有用的替代方法。
LoginRequiredMixin
mixin¶使用基于类的视图时,可以使用 LoginRequiredMixin
实现和 login_required
相同的行为。这个 Mixin 应该在继承列表中最左侧的位置。
LoginRequiredMixin
¶如果一个视图使用 Mixin ,那么未经验证用户的所有请求都会被重定向到登录页面或者显示 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
装饰器一样,Mixin 不会检查用户的 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()
接受一个必要的参数:一个带有:class:~django.contrib.auth.models.User 对象的调用,如果允许用户访问这个页面,则返回 True
。注意,user_passes_test()
不会自动检查用户是否匿名。
user_passes_test()
可以传递两个可选参数:
login_url
settings.LOGIN_URL
。redirect_field_name
login_required()
相同。如果你想把没通过检查的用户重定向到没有 "next page" 的非登录页面时,把它设置为 None
,这样它会在 URL 中移除。例如:
@user_passes_test(email_check, login_url="/login/")
def my_view(request):
...
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()
方法,以使 mixin 对其检查使用不同名称的函数(而不是 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.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
默认是:setting:settings.LOGIN_URL <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
Mixin¶在 class-based views 中应用权限检查,你可以使用 PermissionRequiredMixin
:
PermissionRequiredMixin
¶和 permission_required
装饰器一样,Mixin 检查用户访问的视图是否拥有全部的权限。你应该使用 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
()¶返回 Mixin 使用的可迭代权限的名称。默认为 permission_required
属性,如果需要可以转化为元组。
has_permission
()¶返回布尔值,表示当前用户是否拥有权限执行装饰器视图。默认情况下,这将返回调用 has_perms()
的结果,其中包括返回 get_permission_required()
的权限列表。
为了简化基于类的视图限制访问的处理方式,AccessMixin
被用来配置当访问被拒绝时的视图行为。
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
()¶返回当用户没有通过测试时将被重定向的网址。如果已设置,将返回 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
admin 中,将使用新密码的哈希更新会话,因此用户修改密码后不会被注销。如果你有自定义的密码修改视图,并期望有同样的行为,可以使用 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")),
]
This will include the following URL patterns:
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"),
),
]
所有视图都是基于类的,这就允许你通过子类去方便地自定义它们。
这是一个 django.contrib.auth
提供的所有视图列表。有关实现细节可参考 使用视图 。
LoginView
¶URL name: login
有关使用命名 URL 模式的细节可参考 the URL documentation 。
**方法和属性*
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
,其他网站通过重定向请求你的网站的图片文件的方式来确定他们的访客是否是你网站的已验证用户。为了避免这个 "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
调用,它将显示 POST 到同一 URL 地址的登录表单。稍后会详细介绍。POST
调用,那它将试着让用户登录。如果登录成功,那么视图将重定向到 next
指定的 URL 。如果没有提供 next
,它将重定向到 settings.LOGIN_REDIRECT_URL
(默认 /accounts/profile/
)。如果登录没有成功,它将重新显示登录表单。你需要提供登录模板,默认调用 registration/login.html
。这个模板传递四个模板上下文变量:
form
:一个代表 AuthenticationForm
的 Form
对象。next
:登录成功后跳转的网址。这可能包含查询字段。site
:根据 SITE_ID
设置的当前站点。如果你还没有安装站点框架,会将其设置为 RequestSite
实例,该实例从当前 HttpRequest
中派生出站点名和域名。site_name
:site.name
的别名。如果你还没有按照站点框架,它将设置为 request.META['SERVER_NAME']
的值。更多关于站点信息,请参考 “站点”框架 。如果你不愿意调用模板 registration/login.html
,你可以通过附加参数的形式传递 template_name
参数给你的 URLconf 中的 as_view
方法。比如,这行 URLconf 将使用 myapp/login.html
代替:
path("accounts/login/", auth_views.LoginView.as_view(template_name="myapp/login.html")),
你也可以使用 redirect_field_name
指定 GET
字段的名称,这个字段包含登陆后跳转的 URL 地址。默认情况下,这个字段为 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
属性来使用自定义的验证码模板。此表单必须在它的 __init__()
方法中接受 request
关键字参数,并且提供一个返回已验证用户对象的 get_user()
方法(这个方法只会在表单成功验证后调用)。
LogoutView
¶Logs a user out on POST
requests.
4.1 版后已移除: Support for logging out on GET
requests is deprecated and will be
removed in Django 5.0.
URL name: 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
.
Template context:
title
:字符串 "已注销",已本地化。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 name: 没有提供默认的 URL
可选参数:
login_url
:要重定向到登录页面的 URL 。如果没有提供,默认是 settings.LOGIN_URL
。4.1 版后已移除: Support for logging out on GET
requests is deprecated and will be
removed in Django 5.0.
PasswordChangeView
¶URL name: 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
¶密码修改成功后跳转的 URL 。默认是 '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.
Template context:
form
:密码修改表单(参考上面的 form_class
)PasswordChangeDoneView
¶URL name: 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.
PasswordResetView
¶URL name: password_reset
允许用户通过生成的一次性链接来重置密码,并把一次性链接发到用户注册邮箱中。
This view will send an email if the following conditions are met:
User.is_active
is True
).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.
备注
Be aware that sending an email costs extra time, hence you may be vulnerable to an email address enumeration timing attack due to a difference between the duration of a reset request for an existing email address and the duration of a reset request for a nonexistent email address. To reduce the overhead, you can use a 3rd party package that allows to send emails asynchronously, e.g. 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
¶一个合法的邮件地址。默认情况下,Django 使用 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
.
Template context:
form
:重置用户密码的表单(可参考上面的 form_class
)。电子邮件模板上下文:
email
:user.email
的别名。user
:根据电子邮件表单字段指定的当前用户。只有活动用户才可以重置密码( User.is_active 为 True
)。site_name
:site.name
的别名。如果你还没有按照站点框架,它将设置为 request.META['SERVER_NAME']
的值。更多关于站点信息,请参考 “站点”框架 。domain
:site.domain
的别名。如果你还没有安装网站框架,它会被设置为 request.get_host()
的值。protocol
:http 或 httpsuid
:使用 Base64 编码过的用户主键。token
:检测重置密码链接是否有效的 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 %}
相同的模板上下文用于主题模板。主题必须是单行纯文本字符串。
PasswordResetDoneView
¶URL name: password_reset_done
发送重置密码邮件后显示的页面。如果 PasswordResetView
没有明确设置 success_url
,那么默认将该视图调用。
备注
如果提供的电子邮件地址在系统内并不存在,那么用户可能是非活动用户,或者密码不可被更改。用户仍然会重定向到这个视图,但不会发送邮件。
属性:
template_name
¶被使用模板的全称。如果没有提供,则默认是 registration/password_reset_done.html
extra_context
¶A dictionary of context data that will be added to the default context data passed to the template.
PasswordResetConfirmView
¶URL name: password_reset_confirm
提供输入新密码的表单。
URL 的关键参数
uidb64
:被Base64编码过的用户 id。token
:检查密码是否有效的 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
¶A dictionary of context data that will be added to the default context data passed to the template.
reset_url_token
¶Token 参数为密码重置链接的组成部分。默认是 'set-password'
。
Template context:
form
:用来设置用户新密码的表单(查看上面的 form_class
)。validlink
:布尔值,如果链接(uidb64
和 token
的组合)有效且合法,则返回 True 。redirect_to_login
(next, login_url=None, redirect_field_name='next')¶重定向到登录页面,登陆成功后跳转到其他 URL 。
必要参数
next
:成功登陆后跳转的 URL。可选参数:
login_url
:要重定向到登录页面的 URL 。如果没有提供,默认是 settings.LOGIN_URL
。redirect_field_name
:注销后跳转的 URL 所包含的 GET
字段名称。如果已传递给定的 GET
参数,则覆盖 next
。如果你不想使用内置视图,但希望不必为此功能编写表单,验证系统提供很多在 django.contrib.auth.forms
中的内置表单。
备注
内置验证表单对用户正在使用的的用户模型做了某些假设。如果你正在使用 custom user model ` ,它可能需要为验证系统定义你自己的表单。如需了解更多信息,参考文档 :ref:`using the built-in authentication forms with custom user models 。
AdminPasswordChangeForm
¶在管理界面修改用户密码所使用的表单。
将 user
作为第一个参数。
AuthenticationForm
¶用户登录的表单。
将 request
作为第一个参数,该参数存储在表单实例上,供子类使用。
confirm_login_allowed
(user)¶默认情况下,AuthenticationForm
拒绝 is_active
标识为 False
的用户。你可以通过自定义策略来覆盖这个行为来决定哪个用户可以登录。通过``AuthenticationForm`` 子类的自定义表单来执行这个操作,并覆盖 confirm_login_allowed()
方法。如果给定的用户无法登录,这个方法应该引发 ValidationError
错误。
举例,允许所有用户登录而不管 "active" 状态:
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",
)
PasswordChangeForm
¶允许用户修改密码的表单:
PasswordResetForm
¶生成和邮件发送一次性重置密码链接的表单。
send_mail
(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)¶使用参数发送 EmailMultiAlternatives
。可以重写自定义邮件发送给用户的方式。
参数: |
|
---|
默认情况下,save()
使用 PasswordResetView
传递给其电子邮件上下文的相同变量填充上下文。
SetPasswordForm
¶让用户不输入旧密码就能改变它们密码的表单。
UserChangeForm
¶在管理界面修改用户信息和权限的表单。
BaseUserCreationForm
¶A ModelForm
for creating a new user. This is the
recommended base class if you need to customize the user creation form.
它有三个字段: username
(来自用户模型),password1
,和 password2
。它检查 password1
和 password2
是否匹配,使用 validate_password()
验证密码,并且使用 set_password()
来设置用户密码。
UserCreationForm
¶Inherits from BaseUserCreationForm
. To help prevent confusion with
similar usernames, the form doesn't allow usernames that differ only in
case.
In older versions, UserCreationForm
didn't save many-to-many
form fields for a custom user model.
In older versions, usernames that differ only in case are allowed.
当你使用 RequestContext
时,当前已登录用户和他们的权限在 :doc:`template context ` 中是可用的。
技术细节
从技术上讲,如果你使用 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
的一个实例,它是一个对模板友好的权限代理。
Evaluating a single-attribute lookup of {{ perms }}
as a boolean is a proxy
to User.has_module_perms()
. For example, to check if
the logged-in user has any permissions in the foo
app:
{% if perms.foo %}
Evaluating a two-level-attribute lookup as a boolean is a proxy to
User.has_perm()
. For example,
to check if the logged-in user has the permission foo.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 模型。可以创建组,也可以为用户和组分配权限。用户操作模型的日志也会在管理后台中保存和显示。
你可以在管理后台主页的 “认证和权限” 部分看到 “用户” 链接。“增加用户”的管理界面和其他标准的管理后台不同的是:你需要先输入一个新用户名和新密码,然后才能编辑新用户的剩余字段。
注意:如果你希望某个用户账号可以在 Django 管理后台创建用户,你将需要给用户“创建”和“修改”权限。如果账号只有“创建”权限但没有“修改”权限,那么这个账号将不能增加用户。为什么?因为你有权限添加用户,那么你就拥有添加超级管理员的权利,而超级管理员就可以修改其他用户。因此,Django 需要添加和修改权限作为安全措施。
要考虑如何允许用户去管理权限。如果你允许普通管理员编辑用户,这和给他们超级管理员权限一样。因为他们有权利提升用户权限,包括他们自己。
用户密码不显示在管理界面中(也不在数据库中保存),但会显示 password storage details 。这个信息中包含一个指向密码修改表单的链接,该表单允许管理员修改用户密码。
5月 31, 2023