使用 Django 身份验证系统¶
本文档说明了 Django 身份验证系统在其默认配置中的用法。此配置已发展到可以满足最常见的项目需求,处理相当广泛的任务,并且对密码和权限进行了细致的实现。对于身份验证需求与默认设置不同的项目,Django 支持对身份验证进行广泛的扩展和自定义。
Django 身份验证同时提供身份验证和授权,通常称为身份验证系统,因为这些功能在某种程度上是耦合的。
User
对象¶
User
对象是身份验证系统的核心。它们通常代表与你的网站进行交互的人,并且用于启用诸如限制访问、注册用户个人资料、将内容与创建者关联等功能。Django 的身份验证框架中只存在一类用户,即 '超级用户'
或管理员 '员工'
用户只是设置了特殊属性的用户对象,而不是不同类别的用户对象。
默认用户的基本属性是
请参阅 完整 API 文档
以获得完整参考,以下文档更面向任务。
创建用户¶
创建用户的最直接方式是使用包含的 create_user()
帮助程序函数
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user("john", "[email protected]", "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 管理,您还可以 交互式创建用户。
创建超级用户¶
使用 createsuperuser
命令创建超级用户
$ python manage.py createsuperuser --username=joe --email=[email protected]
...\> py manage.py createsuperuser --username=joe [email protected]
系统将提示您输入密码。输入密码后,将立即创建用户。如果您没有关闭 --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 管理,您还可以在 身份验证系统的管理页面 上更改用户的密码。
Django 还提供了 视图 和 表单,可用于允许用户更改自己的密码。
更改用户的密码将注销其所有会话。有关详细信息,请参阅 密码更改时的会话失效。
验证用户¶
-
authenticate
(request=None, **credentials)¶
-
aauthenticate
(request=None, **credentials)¶ 异步版本:
aauthenticate()
使用
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 credentials ...
request
是一个可选的HttpRequest
,它传递给验证后端的authenticate()
方法。注意
这是验证一组凭证的低级方法;例如,它由
RemoteUserMiddleware
使用。除非您正在编写自己的验证系统,否则您可能不会使用它。相反,如果您正在寻找一种登录用户的方法,请使用LoginView
。在 Django 5.0 中更改添加了
aauthenticate()
函数。
权限和授权¶
Django 带有一个内置权限系统。它提供了一种向特定用户和用户组分配权限的方法。
Django 管理员站点使用它,但欢迎您在自己的代码中使用它。
Django 管理员站点使用权限如下
- 查看对象的访问权限仅限于具有该类型对象的“查看”或“更改”权限的用户。
- 查看“添加”表单并添加对象的访问权限仅限于具有该类型对象的“添加”权限的用户。
- 查看更改列表、查看“更改”表单和更改对象的访问权限仅限于具有该类型对象的“更改”权限的用户。
- 删除对象的访问权限仅限于具有该类型对象的“删除”权限的用户。
权限不仅可以针对每种类型的对象设置,还可以针对特定对象实例设置。通过使用 has_view_permission()
、has_add_permission()
、has_change_permission()
和 has_delete_permission()
方法,由 ModelAdmin
类提供,可以自定义相同类型的不同对象实例的权限。
User
对象有两个多对多字段:groups
和 user_permissions
。 User
对象可以像访问任何其他 Django 模型 一样访问它们的相关对象
myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()
默认权限¶
当 django.contrib.auth
在您的 INSTALLED_APPS
设置中列出时,它将确保为在您的已安装应用程序之一中定义的每个 Django 模型创建四个默认权限 – 添加、更改、删除和查看。
当您运行 manage.py migrate
时,将创建这些权限;在将 django.contrib.auth
添加到 INSTALLED_APPS
后首次运行 migrate
时,将为所有先前安装的模型以及当时安装的所有新模型创建默认权限。之后,每次运行 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
类中,但你也可以直接创建权限。例如,你可以为 myapp
中的 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
的 user_permissions
属性或通过 Group
的 permissions
属性将权限分配给 User
或 Group
。
代理模型需要自己的内容类型
如果你想为 代理模型创建权限,请将 for_concrete_model=False
传递给 ContentTypeManager.get_for_model()
以获取适当的 ContentType
content_type = ContentType.objects.get_for_model(
BlogPostProxy, for_concrete_model=False
)
权限缓存¶
首次需要获取ModelBackend
权限检查后,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
Web 请求中的身份验证¶
Django 使用会话和中间件将身份验证系统连接到请求 对象
。
它们在每个请求上提供request.user
属性和request.auser
异步方法,表示当前用户。如果当前用户尚未登录,此属性将设置为AnonymousUser
的实例,否则将是User
的实例。
您可以使用is_authenticated
将它们区分开来,如下所示
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
或在异步视图中
user = await request.auser()
if user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
添加了HttpRequest.auser()
方法。
如何让用户登录¶
如果您有一个经过身份验证的用户想要附加到当前会话 - 这是通过login()
函数完成的。
-
login
(request, user, backend=None)¶
-
alogin
(request, user, backend=None)¶ 异步版本:
alogin()
要从视图登录用户,请使用
login()
。它采用HttpRequest
对象和User
对象。login()
使用 Django 的会话框架将用户的 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. ...
在 Django 5.0 中更改添加了
alogin()
函数。
选择认证后端¶
当用户登录时,用户的 ID 和用于认证的后端将保存在用户的会话中。这允许相同的 认证后端 在将来的请求中获取用户的详细信息。要保存在会话中的认证后端选择如下
- 如果提供了可选
backend
参数,请使用其值。 - 如果存在,请使用
user.backend
属性的值。这允许配对authenticate()
和login()
:authenticate()
在它返回的用户对象上设置user.backend
属性。 - 如果只有一个,请在
AUTHENTICATION_BACKENDS
中使用backend
。 - 否则,引发异常。
在情况 1 和 2 中,backend
参数或 user.backend
属性的值应为带点的导入路径字符串(如 AUTHENTICATION_BACKENDS
中找到的那样),而不是实际的后端类。
如何注销用户¶
-
logout
(request)¶
-
alogout
(request)¶ 异步版本:
alogout()
要注销通过
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()
时,当前请求的会话数据将被彻底清除。所有现有数据都将被删除。这是为了防止其他人使用同一 Web 浏览器登录并访问前一个用户的会话数据。如果您希望在用户注销后立即向会话中添加任何内容,请在调用django.contrib.auth.logout()
之后 执行此操作。在 Django 5.0 中更改添加了
alogout()
函数。
限制对已登录用户的访问¶
原始方法¶
限制对页面的访问的原始方法是检查 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
和您的登录视图已正确关联。例如,使用默认值,将以下行添加到您的 URLconffrom 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()
的有用替代方案。
LoginRequiredMixin
混合¶
使用 基于类的视图 时,可以通过使用 LoginRequiredMixin
来实现与 login_required
相同的行为。此混合应位于继承列表的最左侧。
-
class
LoginRequiredMixin
¶ 如果视图使用此混合,则所有未经身份验证用户的请求都将根据
raise_exception
参数重定向到登录页面或显示 HTTP 403 禁止错误。可以设置
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
的redirect_authenticated_user=True
并且已登录用户不具有所有必需的权限时,这也避免了重定向循环。
PermissionRequiredMixin
混合¶
若要将权限检查应用于 基于类的视图,可以使用 PermissionRequiredMixin
-
class
PermissionRequiredMixin
¶ 此 mixin 就像
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
()¶ 返回 mixin 使用的权限名称的迭代。默认为
permission_required
属性,必要时转换为元组。
-
has_permission
()¶ 返回一个布尔值,表示当前用户是否有权执行装饰的视图。默认情况下,这会返回调用
has_perms()
的结果,其中权限列表由get_permission_required()
返回。
-
在基于类的视图中重定向未授权的请求¶
为了简化 基于类的视图 中的访问限制处理,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
,则返回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
和 django.contrib.auth
管理中的 user_change_password
视图,会使用新密码哈希更新会话,以便更改自己密码的用户不会退出登录。如果您有自定义密码更改视图并希望有类似的行为,请使用 update_session_auth_hash()
函数。
-
update_session_auth_hash
(request, user)¶
-
aupdate_session_auth_hash
(request, user)¶ 异步版本:
aupdate_session_auth_hash()
此函数获取当前请求和更新后的用户对象(新会话哈希将由此派生),并适当地更新会话哈希。它还会轮换会话密钥,以便使窃取的会话 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: ...
在 Django 5.0 中更改添加了
aupdate_session_auth_hash()
函数。
注意
由于 get_session_auth_hash()
基于 SECRET_KEY
,因此在将您的网站更新为使用新密钥时,必须轮换密钥值以避免使现有会话失效。有关详细信息,请参阅 SECRET_KEY_FALLBACKS
。
身份验证视图¶
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
。
-
next_page
¶ 登录后要重定向到的 URL。默认为
LOGIN_REDIRECT_URL
。
-
redirect_field_name
¶ 包含登录后重定向到的 URL 的
GET
字段的名称。默认为next
。如果传递给定的GET
参数,则会覆盖get_default_redirect_url()
URL。
-
authentication_form
¶ 用于身份验证的可调用对象(通常是表单类)。默认为
AuthenticationForm
。
-
extra_context
¶ 将添加到传递给模板的默认上下文数据中的上下文数据字典。
-
redirect_authenticated_user
¶ 控制访问登录页面的已验证用户是否会被重定向,就像他们刚刚成功登录一样的一个布尔值。默认为
False
。警告
如果您启用
redirect_authenticated_user
,其他网站将能够通过请求您网站上的图像文件的重定向 URL 来确定其访问者是否在您的网站上经过身份验证。为了避免这种“社交媒体指纹识别”信息泄露,请将所有图像和 favicon 托管在单独的域上。启用
redirect_authenticated_user
还会在使用permission_required()
装饰器时导致重定向循环,除非使用raise_exception
参数。
-
success_url_allowed_hosts
¶ 除了
request.get_host()
之外的主机的一个set
,在登录后重定向时是安全的。默认为一个空的set
。
-
get_default_redirect_url
()¶ 返回登录后要重定向到的 URL。默认实现解析并返回
next_page
(如果已设置),否则返回LOGIN_REDIRECT_URL
。
以下是
LoginView
的作用- 如果通过
GET
调用,它会显示一个登录表单,该表单会将 POST 请求发送到同一个 URL。稍后会详细介绍这一点。 - 如果通过
POST
调用并带有用户提交的凭据,它会尝试让用户登录。如果登录成功,该视图会重定向到next
中指定的 URL。如果未提供next
,它会重定向到settings.LOGIN_REDIRECT_URL
(默认为/accounts/profile/
)。如果登录不成功,它会重新显示登录表单。
你有责任提供登录模板的 html,默认情况下称为
registration/login.html
。此模板会传递四个模板上下文变量form
:表示AuthenticationForm
的Form
对象。next
:成功登录后要重定向到的 URL。它可能也包含一个查询字符串。站点
:当前站点
,根据SITE_ID
设置。如果您未安装站点框架,这将设置为RequestSite
的实例,该实例从当前HttpRequest
派生站点名称和域名。站点名称
:site.name
的别名。如果您未安装站点框架,这将设置为request.META['SERVER_NAME']
的值。有关站点的更多信息,请参见 “站点”框架。
如果您不想调用模板
registration/login.html
,您可以通过as_view
方法中的额外参数传递template_name
参数。例如,此 URLconf 行将使用myapp/login.html
path("accounts/login/", auth_views.LoginView.as_view(template_name="myapp/login.html")),
您还可以使用
redirect_field_name
指定包含登录后重定向到的 URL 的GET
字段的名称。默认情况下,该字段称为next
。以下是一个示例
registration/login.html
模板,您可以将其用作起点。它假定您有一个定义content
块的base.html
模板{% 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 %}
如果您已自定义身份验证(请参见 自定义身份验证),您可以通过设置
authentication_form
属性来使用自定义身份验证表单。此表单必须在其__init__()
方法中接受request
关键字参数,并提供一个get_user()
方法,该方法返回经过身份验证的用户对象(此方法仅在表单验证成功后调用)。-
-
类
LogoutView
¶ 在
POST
请求上注销用户。URL 名称:
logout
属性
-
next_page
¶ 注销后要重定向到的 URL。默认为
LOGOUT_REDIRECT_URL
。
-
template_name
¶ 注销用户后要显示的模板的全名。默认为
registration/logged_out.html
。
-
extra_context
¶ 将添加到传递给模板的默认上下文数据中的上下文数据字典。
-
success_url_allowed_hosts
¶ 除了
request.get_host()
之外,还可以安全重定向到的一组主机,默认为一个空set
。
模板上下文
title
:已本地化的字符串“已注销”。站点
:当前站点
,根据SITE_ID
设置。如果您未安装站点框架,这将设置为RequestSite
的实例,该实例从当前HttpRequest
派生站点名称和域名。站点名称
:site.name
的别名。如果您未安装站点框架,这将设置为request.META['SERVER_NAME']
的值。有关站点的更多信息,请参见 “站点”框架。
-
-
logout_then_login
(request, login_url=None)¶ 在
POST
请求中注销用户,然后重定向到登录页面。URL 名称:未提供默认 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
允许用户通过生成一次性使用的链接来重置密码,该链接可用于重置密码,并将该链接发送到用户的注册电子邮件地址。
如果满足以下条件,此视图将发送电子邮件
- 系统中存在提供的电子邮件地址。
- 请求的用户处于活动状态(
User.is_active
为True
)。 - 请求的用户具有可用的密码。使用不可用密码标记的用户(请参阅
set_unusable_password()
)不允许请求重置密码,以防止在使用 LDAP 等外部身份验证源时被滥用。
如果不满足这些条件中的任何一个,则不会发送电子邮件,但用户也不会收到任何错误消息。这可以防止信息泄露给潜在的攻击者。如果您想在这种情况下提供错误消息,您可以对
PasswordResetForm
进行子类化并使用form_class
属性。注意
请注意,发送电子邮件需要额外的时间,因此由于现有电子邮件地址的重置请求持续时间和不存在的电子邮件地址的重置请求持续时间之间的差异,您可能会受到电子邮件地址枚举时序攻击的攻击。为了减少开销,您可以使用允许异步发送电子邮件的第三方包,例如 django-mailer。
属性
-
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
:根据email
表单字段,当前的User
。只有活动用户才能重置其密码(User.is_active is True
)。站点名称
:site.name
的别名。如果您未安装站点框架,这将设置为request.META['SERVER_NAME']
的值。有关站点的更多信息,请参见 “站点”框架。domain
:site.domain
的别名。如果您没有安装站点框架,则将其设置为request.get_host()
的值。protocol
:http 或 httpsuid
:以 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_url
URL,则默认调用此视图。注意
如果系统中不存在提供的电子邮件地址,用户处于非活动状态或密码不可用,用户仍将被重定向到此视图,但不会发送电子邮件。
属性
-
template_name
¶ 要使用的模板的全名。如果未提供,则默认为
registration/password_reset_done.html
。
-
extra_context
¶ 将添加到传递给模板的默认上下文数据中的上下文数据字典。
-
-
class
PasswordResetConfirmView
¶ URL 名称:
password_reset_confirm
显示一个用于输入新密码的表单。
URL 中的关键字参数
uidb64
:以 base 64 编码的用户 ID。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
:布尔值,如果链接(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
中的内置表单。
注意
内置身份验证表单对它们所使用的用户模型做出了一些假设。如果你正在使用 自定义用户模型,则可能需要为身份验证系统定义你自己的表单。有关更多信息,请参阅有关 将内置身份验证表单与自定义用户模型一起使用 的文档。
-
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()
用PasswordResetView
传递给其电子邮件上下文的相同变量填充context
。
-
-
class
SetPasswordForm
¶ 一种允许用户在不输入旧密码的情况下更改其密码的表单。
-
class
UserChangeForm
¶ 在管理界面中用于更改用户信息和权限的表单。
-
class
BaseUserCreationForm
¶ - Django 4.2 中的新增功能。
用于创建新用户的
ModelForm
。如果您需要自定义用户创建表单,这是推荐的基本类。它有三个字段:
username
(来自用户模型)、password1
和password2
。它验证password1
和password2
是否匹配,使用validate_password()
验证密码,并使用set_password()
设置用户的密码。
-
类
UserCreationForm
¶ 继承自
BaseUserCreationForm
。为了帮助避免与类似用户名混淆,该表单不允许仅在大小写上有所不同的用户名。
模板中的身份验证数据¶
当你使用 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”部分中看到一个指向“Users”的链接。“添加用户”管理页面不同于标准管理页面,因为它要求你在允许你编辑用户其余字段之前选择一个用户名和密码。
另请注意:如果你希望用户帐户能够使用 Django 管理网站创建用户,则需要授予他们添加用户和更改用户的权限(即“添加用户”和“更改用户”权限)。如果一个帐户有权添加用户但无权更改用户,则该帐户将无法添加用户。为什么?因为如果你有权添加用户,则你有权创建超级用户,然后超级用户又可以更改其他用户。因此,Django 要求添加和更改权限作为轻微的安全措施。
要深思熟虑地允许用户管理权限。如果你授予非超级用户编辑用户的权限,这最终等同于授予他们超级用户状态,因为他们将能够提升包括他们自己在内的用户的权限!