使用 Django 认证系统 — Django 文档

来自菜鸟教程
Django/docs/3.2.x/topics/auth/default
跳转至:导航、​搜索

使用 Django 认证系统

本文档解释了 Django 认证系统在其默认配置中的用法。 这种配置已经发展到可以满足最常见的项目需求,处理相当广泛的任务,并仔细实施密码和权限。 对于认证需求与默认不同的项目,Django 支持广泛的 扩展和定制 认证。

Django 身份验证同时提供身份验证和授权,通常称为身份验证系统,因为这些功能有些耦合。

User 物体

User 对象是认证系统的核心。 它们通常代表与您的网站交互的人,用于启用诸如限制访问、注册用户配置文件、将内容与创建者相关联等功能。 Django 的认证框架中只存在一类用户,即 'superusers' 或 admin 'staff' 用户只是设置了特殊属性的用户对象,不是不同类的用户对象。

默认用户的主要属性是:

请参阅 完整 API 文档 以获取完整参考,随后的文档更面向任务。

创建用户

创建用户最直接的方法是使用包含的 create_user() 辅助函数:

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

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

如果你安装了 Django admin,你还可以【X53X】交互创建用户【X83X】。


创建超级用户

使用 :djadmin:`createsuperuser` 命令创建超级用户:

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

系统将提示您输入密码。 输入后,用户将立即创建。 如果您不使用 --username--email 选项,它会提示您输入这些值。


更改密码

Django 不会在用户模型上存储原始(明文)密码,而只会存储散列(有关详细信息,请参阅 密码管理文档 )。 因此,不要试图直接操作用户的密码属性。 这就是创建用户时使用辅助函数的原因。

要更改用户的密码,您有多种选择:

:djadmin:`manage.py 更改密码 *用户名* ` 提供了一种从命令行更改用户密码的方法。 它会提示您更改给定用户的密码,您必须输入两次。 如果两者匹配,新密码将立即更改。 如果您不提供用户,该命令将尝试更改用户名与当前系统用户匹配的密码。

您还可以使用 set_password() 以编程方式更改密码:

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

如果您安装了 Django 管理员,您还可以在 身份验证系统的管理页面 上更改用户密码。

Django 还提供了 viewsforms,可用于允许用户更改自己的密码。

更改用户的密码将注销其所有会话。 有关详细信息,请参阅 更改密码时会话失效


验证用户

authenticate(request=None, **credentials)

使用 authenticate() 验证一组凭据。 它将凭据作为关键字参数,默认情况下为 usernamepassword,根据每个 身份验证后端 检查它们,并返回一个 User 对象,如果凭据对后端有效。 如果凭据对任何后端都无效,或者如果后端引发 PermissionDenied,则返回 None。 例如:

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

request 是一个可选的 HttpRequest,它在身份验证后端的 authenticate() 方法上传递。

笔记

这是验证一组凭据的低级方法; 例如,它被 RemoteUserMiddleware 使用。 除非您正在编写自己的身份验证系统,否则您可能不会使用它。 相反,如果您正在寻找一种登录用户的方法,请使用 LoginView


权限和授权

Django 带有一个内置的权限系统。 它提供了一种向特定用户和用户组分配权限的方法。

它由 Django 管理站点使用,但欢迎您在自己的代码中使用它。

Django 管理站点使用的权限如下:

  • 对查看对象的访问仅限于对该类型对象具有“查看”或“更改”权限的用户。
  • 查看“添加”表单和添加对象的访问权限仅限于对该类型对象具有“添加”权限的用户。
  • 查看更改列表、查看“更改”表单和更改对象的访问权限仅限于对该类型对象具有“更改”权限的用户。
  • 删除对象的访问权限仅限于对该类型对象具有“删除”权限的用户。

不仅可以按对象类型设置权限,还可以按特定对象实例设置权限。 通过使用 has_view_permission()has_add_permission()has_change_permission()has_delete_permission()X17 提供的方法X17 类,可以为同一类型的不同对象实例自定义权限。

User 对象有两个多对多字段:groupsuser_permissionsUser 对象可以像任何其他 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 列在您的 :setting:`INSTALLED_APPS` 设置中时,它将确保为在您已安装的应用程序之一。

这些权限将在您运行时创建 :djadmin:`manage.py 迁移 ` ; 第一次跑步migrate添加后django.contrib.auth:设置:`INSTALLED_APPS` ,将为所有以前安装的模型以及当时安装的任何新模型创建默认权限。 之后,每次运行时它都会为新模型创建默认权限 :djadmin:`manage.py 迁移 ` (创建权限的函数连接到迁移后信号)。

假设您有一个带有 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_permissions 属性将权限分配给 用户 ,或通过 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

Web 请求中的身份验证

Django 使用 会话 和中间件将身份验证系统挂接到 请求对象

这些在代表当前用户的每个请求上提供 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() 在会话中保存用户的 ID,使用 Django 的会话框架。

请注意,匿名会话期间设置的任何数据在用户登录后都会保留在会话中。

此示例显示了如何同时使用 authenticate()login()

from django.contrib.auth import authenticate, login

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

选择认证后端

当用户登录时,用户的 ID 和用于身份验证的后端将保存在用户的会话中。 这允许相同的 身份验证后端 在未来的请求中获取用户的详细信息。 要保存在会话中的身份验证后端选择如下:

  1. 使用可选的 backend 参数的值(如果提供)。
  2. 使用 user.backend 属性的值(如果存在)。 这允许配对 authenticate()login()authenticate() 在它返回的用户对象上设置 user.backend 属性。
  3. 使用 :setting:`AUTHENTICATION_BACKENDS` 中的 backend,如果只有一个。
  4. 否则,引发异常。

在情况 1 和 2 中,backend 参数或 user.backend 属性的值应该是带点的导入路径字符串(就像在 :setting:`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() 时,当前请求的会话数据将被完全清除。 删除所有现有数据。 这是为了防止其他人使用相同的 Web 浏览器登录并访问先前用户的会话数据。 如果您想在注销后立即将任何内容放入用户可用的会话中,请在 after 调用 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() 执行以下操作:

  • 如果用户未登录,则重定向到 :setting:`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参数,您需要确保 :setting:`settings.LOGIN_URL ` 并且您的登录视图已正确关联。 例如,使用默认值,将以下行添加到您的 URLconf:

from django.contrib.auth import views as auth_views

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

:setting:`settings.LOGIN_URL ` 还接受视图函数名称和命名的 URL 模式 . 这允许您在 URLconf 中自由地重新映射您的登录视图,而无需更新设置。

笔记

login_required 装饰器不检查用户的 is_active 标志,但默认的 :setting:`AUTHENTICATION_BACKENDS` 拒绝非活动用户。


也可以看看

如果您正在为 Django 的管理员编写自定义视图(或需要与内置视图使用相同的授权检查),您可能会发现 django.contrib.admin.views.decorators.staff_member_required() 装饰器login_required() 的有用替代品。


LoginRequired 混合

使用 基于类的视图 时,您可以通过使用 LoginRequiredMixin 实现与 login_required 相同的行为。 这个 mixin 应该在继承列表的最左边的位置。

class 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 标志,但默认的 :setting:`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。 它可能是一个登录页面,默认为 :setting:`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() 方法,让 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.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_url 默认为 :setting:`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):
    ...

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

返回混合使用的权限名称的迭代。 默认为 permission_required 属性,必要时转换为元组。

has_permission()

返回一个布尔值,表示当前用户是否有权执行装饰视图。 默认情况下,这将返回使用 get_permission_required() 返回的权限列表调用 has_perms() 的结果。


在基于类的视图中重定向未经授权的请求

为了简化基于类的视图中访问限制的处理,AccessMixin可用于配置访问被拒绝时的视图行为。 通过 HTTP 403 Forbidden 响应拒绝经过身份验证的用户访问。 匿名用户被重定向到登录页面或显示 HTTP 403 Forbidden 响应,具体取决于 raise_exception 属性。

class AccessMixin
login_url

get_login_url() 的默认返回值。 默认为None在这种情况下 get_login_url() 回落到 :setting:`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。 退货登录网址如果设置,或 :setting:`settings.LOGIN_URL ` 除此以外。

get_permission_denied_message()

raise_exceptionTrue 时,此方法可用于控制传递给错误处理程序以显示给用户的错误消息。 默认返回 permission_denied_message 属性。

get_redirect_field_name()

返回查询参数的名称,该参数将包含用户成功登录后应重定向到的 URL。 如果设置为None,则不会添加查询参数。 默认返回 redirect_field_name 属性。

handle_no_permission()

根据 raise_exception 的值,该方法要么引发 PermissionDenied 异常,要么将用户重定向到 login_url,如果是,则可选地包括 redirect_field_name放。

更改密码时会话失效

如果您的 :setting:`AUTH_USER_MODEL` 继承自 AbstractBaseUser 或实现其自己的 get_session_auth_hash() 方法,则经过身份验证的会话将包含此函数返回的哈希值。 在 AbstractBaseUser 情况下,这是密码字段的 HMAC。 Django 验证每个请求的会话中的哈希值是否与请求期间计算的哈希值匹配。 这允许用户通过更改密码注销所有会话。

Django 中包含的默认密码更改视图、PasswordChangeViewdjango.contrib.auth 管理员中的 user_change_password 视图,使用新密码哈希更新会话,以便用户更改自己的密码不会注销自己。 如果您有自定义密码更改视图并希望具有类似行为,请使用 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:
        ...

笔记

由于 get_session_auth_hash() 基于 :setting:`SECRET_KEY`,更新您的站点以使用新密钥将使所有现有会话无效。


身份验证视图

Django 提供了多个视图,可用于处理登录、注销和密码管理。 这些使用 stock auth 表单 ,但您也可以传递自己的表单。

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

网址名称: login

有关使用命名 URL 模式的详细信息,请参阅 URL 文档

属性:

  • template_name:为用于登录用户的视图显示的模板名称。 默认为 registration/login.html

  • redirect_field_name:包含登录后重定向到的 URL 的 GET 字段的名称。 默认为 next

  • authentication_form:用于身份验证的可调用(通常是表单类)。 默认为 AuthenticationForm

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

  • redirect_authenticated_user:一个布尔值,控制访问登录页面的经过身份验证的用户是否将被重定向,就像他们刚刚成功登录一样。 默认为 False

    警告

    如果您启用 redirect_authenticated_user,其他网站将能够通过请求重定向 URL 到您网站上的图像文件来确定他们的访问者是否在您的网站上通过了身份验证。 为避免这种“社交媒体指纹识别”信息泄露,请将所有图像和您的网站图标托管在单独的域中。

    在使用 permission_required() 装饰器时,启用 redirect_authenticated_user 也可能导致重定向循环,除非使用 raise_exception 参数。

  • success_url_allowed_hosts:主机的 set,除了 request.get_host(),登录后重定向是安全的。 默认为空 set

这是 LoginView 的作用:

  • 如果通过 GET 调用,它会显示一个登录表单,该表单发布到相同的 URL。 稍后会详细介绍这一点。

  • 如果使用用户提交的凭据通过 POST 调用,它会尝试登录用户。 如果登录成功,则视图重定向到 next 中指定的 URL。 如果next未提供,它重定向到 :setting:`settings.LOGIN_REDIRECT_URL ` (默认为/accounts/profile/ )。 如果登录不成功,它会重新显示登录表单。

您有责任为登录模板提供 html,默认情况下称为 registration/login.html。 这个模板被传递了四个模板上下文变量:

如果您不想调用模板 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')),

您还可以指定 GET 字段的名称,该字段包含使用 redirect_field_name 登录后要重定向到的 URL。 默认情况下,该字段称为 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 setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

如果您已自定义身份验证(请参阅 自定义身份验证 ),您可以通过设置 authentication_form 属性来使用自定义身份验证表单。 此表单必须在其 __init__() 方法中接受 request 关键字参数,并提供一个 get_user() 方法,该方法返回经过身份验证的用户对象(此方法仅在成功表单验证后调用) .

class LogoutView

注销用户。

网址名称: logout

属性:

  • next_page:注销后重定向到的 URL。 默认为 :setting:`settings.LOGOUT_REDIRECT_URL ` .

  • template_name:用户注销后显示的模板全名。 默认为 registration/logged_out.html

  • redirect_field_nameGET 字段的名称,其中包含注销后要重定向到的 URL。 默认为 next。 如果传递给定的 GET 参数,则覆盖 next_page URL。

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

  • success_url_allowed_hosts:除 request.get_host() 之外的 set 主机,注销后重定向是安全的。 默认为空 set

模板上下文:

logout_then_login(request, login_url=None)

注销用户,然后重定向到登录页面。

URL 名称: 未提供默认 URL

可选参数:

class PasswordChangeView

网址名称: 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

网址名称: password_change_done

用户更改密码后显示的页面。

属性:

  • template_name:要使用的模板的全名。 如果未提供,则默认为 registration/password_change_done.html

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

class PasswordResetView

网址名称: password_reset

允许用户通过生成可用于重置密码的一次性使用链接并将该链接发送到用户注册的电子邮件地址来重置其密码。

如果系统中不存在提供的电子邮件地址,则此视图不会发送电子邮件,但用户也不会收到任何错误消息。 这可以防止信息泄露给潜在的攻击者。 如果您想在这种情况下提供错误消息,您可以子类化 PasswordResetForm 并使用 form_class 属性。

笔记

请注意,发送电子邮件会花费额外的时间,因此您可能容易受到电子邮件地址枚举计时攻击的影响,因为现有电子邮件地址的重置请求持续时间与不存在的电子邮件地址的重置请求持续时间之间存在差异. 为了减少开销,您可以使用允许异步发送电子邮件的第 3 方包,例如 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 使用 :setting:`DEFAULT_FROM_EMAIL`

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

  • html_email_template_name:用于生成带有密码重置链接的 text/html 多部分电子邮件的模板的全名。 默认情况下,不发送 HTML 电子邮件。

  • extra_email_context:电子邮件模板中可用的上下文数据字典。 它可用于覆盖下面列出的默认模板上下文值,例如 domain

模板上下文:

  • form:用于重置用户密码的表单(见上文form_class)。

电子邮件模板上下文:

  • emailuser.email 的别名

  • user:当前用户,根据email表单域。 只有活跃用户才能重置他们的密码 (User.is_active is True)。

  • site_namesite.name 的别名。 如果您没有安装站点框架,这将被设置为 request.META['SERVER_NAME'] 的值。 有关站点的更多信息,请参阅 “站点”框架

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

网址名称: password_reset_done

用户通过电子邮件收到重置密码链接后显示的页面。 如果 PasswordResetView 没有明确的 success_url URL 集,则默认调用此视图。

笔记

如果系统中不存在提供的电子邮件地址、用户处于非活动状态或密码不可用,用户仍将被重定向到此视图,但不会发送电子邮件。

属性:

  • template_name:要使用的模板的全名。 如果未提供,则默认为 registration/password_reset_done.html

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

class PasswordResetConfirmView

网址名称: 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_loginTrue,则在对用户进行身份验证时使用的身份验证后端的虚线路径。 仅当您配置了多个 :setting:`AUTHENTICATION_BACKENDS` 时才需要。 默认为 None

  • form_class:用于设置密码的表格。 默认为 SetPasswordForm

  • success_url:密码重置完成后重定向的 URL。 默认为 'password_reset_complete'

  • extra_context:上下文数据字典,将添加到传递给模板的默认上下文数据中。

  • reset_url_token:作为密码重置 URL 组件显示的令牌参数。 默认为 'set-password'

模板上下文:

  • form:用于设置新用户密码的表单(见上文form_class)。

  • validlink:布尔值,如果链接(uidb64token 的组合)有效或尚未使用,则为真。

class PasswordResetCompleteView

网址名称: 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。 默认为 :setting:`settings.LOGIN_URL ` 如果没有提供。

  • redirect_field_nameGET 字段的名称,其中包含注销后要重定向到的 URL。 如果传递给定的 GET 参数,则覆盖 next


内置表格

如果您不想使用内置视图,但希望不必为此功能编写表单的便利,身份验证系统提供了几个位于 django.contrib.auth.forms[ 的内置表单] X221X]:

笔记

内置的身份验证表单对它们正在使用的用户模型做出了某些假设。 如果您使用 自定义用户模型 ,则可能需要为身份验证系统定义您自己的表单。 有关更多信息,请参阅有关 使用带有自定义用户模型的内置身份验证表单 的文档。


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_templateemail_templatehtml_email_template 的上下文(如果不是 None)。

  • from_email – 发件人的电子邮件。

  • to_email – 请求者的电子邮件。

  • html_email_template_name – HTML 正文的模板; 默认为 None,在这种情况下发送纯文本电子邮件。

默认情况下,save() 使用 PasswordResetView 传递给其电子邮件上下文的相同变量填充 context

class SetPasswordForm
一种让用户无需输入旧密码即可更改密码的表单。
class UserChangeForm
管理界面中用于更改用户信息和权限的表单。
class UserCreationForm

用于创建新用户的 ModelForm

它包含三个字段:username(来自用户模型)、password1password2。 它验证 password1password2 匹配,使用 validate_password() 验证密码,并使用 set_password() 设置用户密码。


模板中的身份验证数据

当您使用 RequestContext 时,当前登录的用户及其权限在 模板上下文 中可用。

技术性

从技术上讲,如果您使用 RequestContext 并且启用了 'django.contrib.auth.context_processors.auth' 上下文处理器,则这些变量仅在模板上下文中可用。 它位于默认生成的设置文件中。 有关更多信息,请参阅 RequestContext 文档


用户

渲染模板 RequestContext 时,当前登录的用户(User 实例或 AnonymousUser 实例)存储在模板变量 [ X192X]:

{% 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.admindjango.contrib.auth 时,管理员提供了一种查看和管理用户、组和权限的便捷方式。 可以像任何 Django 模型一样创建和删除用户。 可以创建组,并且可以为用户或组分配权限。 还会存储和显示用户在管理员中对模型进行编辑的日志。

创建用户

您应该会在主管理索引页面的“身份验证”部分中看到指向“用户”的链接。 “添加用户”管理页面与标准管理页面不同,它要求您在允许您编辑用户的其余字段之前选择用户名和密码。

另请注意:如果您希望用户帐户能够使用 Django 管理站点创建用户,则需要授予他们添加用户 更改用户的权限(即,“添加用户”和“更改用户”权限)。 如果帐户有权添加用户但不能更改用户,则该帐户将无法添加用户。 为什么? 因为如果您有权添加用户,您就有权创建超级用户,然后又可以更改其他用户。 因此,Django 需要添加 更改权限作为轻微的安全措施。

考虑如何允许用户管理权限。 如果您赋予非超级用户编辑用户的能力,这最终与赋予他们超级用户身份相同,因为他们将能够提升包括他们自己在内的用户的权限!


更改密码

用户密码不显示在管理员中(也不存储在数据库中),但显示密码存储详细信息。 此信息的显示中包含一个指向密码更改表单的链接,该表单允许管理员更改用户密码。