使用 Django 身份验证系统

本文档解释了在默认配置下 Django 身份验证系统的用法。此配置已发展到满足最常见的项目需求,处理相当广泛的任务,并仔细实现了密码和权限。对于身份验证需求与默认设置不同的项目,Django 支持对身份验证进行广泛的扩展和定制

Django 身份验证同时提供身份验证和授权功能,通常称为身份验证系统,因为这些功能在某种程度上是耦合的。

User 对象

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

默认用户的首要属性是

请参阅完整的 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 不会在用户模型上存储原始(明文)密码,而只存储哈希值(请参阅密码管理方式文档 获取完整详细信息)。因此,不要尝试直接操作用户的 password 属性。这就是创建用户时使用辅助函数的原因。

要更改用户的密码,您可以选择以下几种方法:

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

您还可以使用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)[source]
aauthenticate(request=None, **credentials)

异步版本aauthenticate()

使用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 5.0 中的更改

添加了aauthenticate() 函数。

权限和授权

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

它被 Django 管理员站点使用,但您也可以在自己的代码中使用它。

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

  • 查看对象的访问权限仅限于拥有该类型对象的“查看”或“更改”权限的用户。

  • 访问“添加”表单并添加对象的权限仅限于拥有该类型对象的“添加”权限的用户。

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

  • 删除对象的访问权限仅限于拥有该类型对象的“删除”权限的用户。

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

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 列在你的 INSTALLED_APPS 设置中时,它将确保为已安装应用程序中定义的每个 Django 模型创建四个默认权限——添加、更改、删除和查看。

运行 manage.py migrate 时将创建这些权限;首次在将 django.contrib.auth 添加到 INSTALLED_APPS 后运行 migrate 时,将为之前安装的所有模型以及当时安装的任何新模型创建默认权限。之后,每次运行 manage.py migrate(创建权限的函数连接到 post_migrate 信号)时,它将为新模型创建默认权限。

假设你有一个应用程序,其 app_labelfoo,并且有一个名为 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 属性将权限分配给 User,或通过其 permissions 属性分配给 Group

代理模型需要自己的内容类型

如果你想创建 代理模型的权限,请将 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 objects

这些为每个请求提供了一个 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.
    ...
Django 5.0 中的更改

添加了 HttpRequest.auser() 方法。

如何登录用户

如果你有一个要附加到当前会话的已认证用户,则可以使用 login() 函数。

login(request, user, backend=None)[source]
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 和用于身份验证的后端将保存在用户的会话中。这允许相同的 身份验证后端 在将来的请求中获取用户的详细信息。保存到会话中的身份验证后端选择如下

  1. 如果提供,则使用可选的 backend 参数的值。

  2. 如果存在,则使用user.backend属性的值。这允许authenticate()login()配对:authenticate()在其返回的用户对象上设置user.backend属性。

  3. 如果只有一个,则使用AUTHENTICATION_BACKENDS中的backend

  4. 否则,引发异常。

在情况1和2中,backend参数的值或user.backend属性应为点导入路径字符串(例如在AUTHENTICATION_BACKENDS中找到的),而不是实际的backend类。

如何注销用户

logout(request)[source]
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()时,当前请求的会话数据将被完全清除。所有现有数据都将被删除。这是为了防止其他人使用相同的网络浏览器登录并访问先前用户的会话数据。如果您想将任何内容放入会话中,以便在注销后立即提供给用户,请在调用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)[source]

作为快捷方式,您可以使用方便的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的admin编写自定义视图(或需要与内置视图使用的相同的授权检查),您可能会发现django.contrib.admin.views.decorators.staff_member_required()装饰器是login_required()的有用替代方案。

Django 5.1 中的更改

添加了对包装异步视图函数的支持。

LoginRequiredMixin mixin

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

class LoginRequiredMixin[source]

如果视图正在使用此mixin,则所有未经身份验证的用户发出的请求都将重定向到登录页面或显示HTTP 403禁止错误,具体取决于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会拒绝非活动用户。

login_not_required装饰器

Django 5.1 新功能。

当安装LoginRequiredMiddleware时,默认情况下所有视图都需要身份验证。某些视图(例如登录视图)可能需要禁用此行为。

login_not_required()[source]

当安装LoginRequiredMiddleware时,允许对此视图进行未经身份验证的请求。

限制通过测试的已登录用户的访问权限

要根据某些权限或其他测试限制访问权限,您需要执行与上一节中描述的相同操作。

您可以直接在视图中对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')[source]

作为快捷方式,您可以使用方便的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): ...
Django 5.1 中的更改

添加了对包装异步视图函数和使用异步测试可调用对象的支持。

class UserPassesTestMixin[source]

当使用基于类的视图时,您可以使用UserPassesTestMixin来实现此目的。

test_func()[source]

您必须重写类的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()[source]

您还可以重写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)[source]

检查用户是否具有特定权限是一项相对常见的任务。为此,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 禁止)视图,而不是重定向到登录页面。

如果您想使用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且已登录用户没有所有必需权限时出现重定向循环。

Django 5.1 中的更改

添加了对包装异步视图函数的支持。

PermissionRequiredMixin mixin

要将权限检查应用于基于类的视图,您可以使用PermissionRequiredMixin

class PermissionRequiredMixin[source]

此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()[source]

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

has_permission()[source]

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

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

为了简化在基于类的视图中访问限制的处理,可以使用AccessMixin来配置拒绝访问时视图的行为。已认证的用户将收到HTTP 403禁止响应。匿名用户将被重定向到登录页面或显示HTTP 403禁止响应,具体取决于raise_exception属性。

class AccessMixin[source]
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()[source]

返回未通过测试的用户将被重定向到的URL。如果设置了login_url,则返回它;否则返回settings.LOGIN_URL

get_permission_denied_message()[source]

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

get_redirect_field_name()[source]

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

handle_no_permission()[source]

根据raise_exception的值,该方法要么引发PermissionDenied异常,要么将用户重定向到login_url,如果设置了redirect_field_name,则可以选择包含它。

更改密码时使会话失效

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

Django包含的默认密码更改视图,PasswordChangeViewdjango.contrib.auth admin中的user_change_password视图,使用新的密码哈希更新会话,以便更改自身密码的用户不会注销自己。如果您有自定义密码更改视图并希望具有类似的行为,请使用update_session_auth_hash()函数。

update_session_auth_hash(request, user)[source]
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 包含在你的 URLconf 中的 django.contrib.auth.urls 中,例如:

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[source]

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()[source]

返回登录后重定向到的 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:一个表示 AuthenticationFormForm 对象。

  • next:成功登录后重定向到的 URL。这也可能包含查询字符串。

  • site:根据 SITE_ID 设置,当前的 Site。如果你没有安装站点框架,这将设置为 RequestSite 的实例,它从当前的 HttpRequest 中导出站点名称和域名。

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

如果你不想调用名为 registration/login.html 的模板,你可以通过 URLconf 中 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() 方法,该方法返回已认证的用户对象(此方法仅在表单验证成功后才会调用)。

class LogoutView[source]

POST 请求上注销用户。

URL 名称:logout

属性

next_page

注销后重定向到的 URL。默认为LOGOUT_REDIRECT_URL

template_name

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

redirect_field_name

包含注销后重定向 URL 的 GET 字段名称。默认为 'next'。如果传递了给定的 GET 参数,则会覆盖 next_page URL。

extra_context

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

success_url_allowed_hosts

除了 request.get_host() 之外,一组用于注销后安全重定向的主机。默认为空 set

模板上下文

  • title:已注销的字符串,已本地化。

  • site:根据 SITE_ID 设置,当前的 Site。如果你没有安装站点框架,这将设置为 RequestSite 的实例,它从当前的 HttpRequest 中导出站点名称和域名。

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

logout_then_login(request, login_url=None)[source]

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

URL 名称:未提供默认 URL

可选参数

  • login_url:要重定向到的登录页面的 URL。如果未提供,则默认为 settings.LOGIN_URL

class PasswordChangeView[source]

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[source]

URL 名称:password_change_done

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

属性

template_name

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

extra_context

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

class PasswordResetView[source]

URL 名称:password_reset

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

如果满足以下条件,此视图将发送电子邮件

  • 提供的邮箱地址存在于系统中。

  • 请求的用户处于活动状态(User.is_activeTrue)。

  • 请求的用户拥有可用的密码。标记为密码不可用的用户(参见 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)。

电子邮件模板上下文

  • emailuser.email 的别名

  • user:根据email表单字段获取的当前User。只有激活用户才能重置密码(User.is_active is True)。

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

  • domainsite.domain的别名。如果您没有安装站点框架,则将其设置为request.get_host()的值。

  • protocol:http 或 https

  • uid:以base64编码的用户主键。

  • 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[source]

URL 名称:password_reset_done

在向用户发送重置密码链接的邮件后显示的页面。如果PasswordResetView没有设置显式的success_url URL,则默认调用此视图。

注意

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

属性

template_name

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

extra_context

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

class PasswordResetConfirmView[source]

URL 名称:password_reset_confirm

显示用于输入新密码的表单。

来自 URL 的关键字参数

  • uidb64:以 base64 编码的用户 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,则在验证用户时使用的身份验证后端的点分路径。只有在配置了多个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的组合)有效或尚未使用,则为 True。

class PasswordResetCompleteView[source]

URL 名称:password_reset_complete

显示一个视图,通知用户密码已成功更改。

属性

template_name

显示视图的模板的全名。默认为registration/password_reset_complete.html

extra_context

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

辅助函数

redirect_to_login(next, login_url=None, redirect_field_name='next')[source]

重定向到登录页面,然后在成功登录后重定向到另一个 URL。

必需参数

  • next:成功登录后要重定向到的 URL。

可选参数

  • login_url:要重定向到的登录页面的 URL。如果未提供,则默认为 settings.LOGIN_URL

  • redirect_field_name:包含登录后要重定向到的 URL 的GET字段的名称。如果传递了给定的GET参数,则会覆盖next

内置表单

如果您不想使用内置视图,但希望方便地不必为该功能编写表单,则身份验证系统提供了位于django.contrib.auth.forms中的几个内置表单。

注意

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

class AdminPasswordChangeForm[source]

在管理界面中用于更改用户密码的表单,包括设置unusable password的功能,这会阻止用户使用基于密码的身份验证登录。

user作为第一个位置参数。

Django 5.1 中的更改

添加了禁用(或重新启用)基于密码的身份验证的选项。

class AdminUserCreationForm[source]
Django 5.1.1 中的新增功能。

在管理界面中用于创建新用户的表单。继承自UserCreationForm

它包含一个额外的usable_password字段,默认启用。如果启用usable_password,它会验证password1password2非空且匹配,使用validate_password()验证密码,并使用set_password()设置用户的密码。如果禁用usable_password,则不会进行密码验证,并且通过调用set_unusable_password()禁用用户的基于密码的身份验证。

class AuthenticationForm[source]

用于用户登录的表单。

request作为其第一个位置参数,该参数存储在表单实例中,供子类使用。

confirm_login_allowed(user)[source]

默认情况下,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 BaseUserCreationForm[source]

用于创建新用户的ModelForm。如果需要自定义用户创建表单,这是推荐的基础类。

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

class PasswordChangeForm[source]

允许用户更改其密码的表单。

class PasswordResetForm[source]

用于生成和发送一次性使用链接以重置用户密码的表单。

send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)[source]

使用参数发送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[source]

允许用户更改其密码而无需输入旧密码的表单。

class UserChangeForm[source]

在管理界面中用于更改用户信息和权限的表单。

class UserCreationForm[source]

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

创建用户

您应该在主管理员索引页面的“Auth”部分看到指向“Users”的链接。“添加用户”管理员页面与标准管理员页面不同,因为它要求您在允许您编辑用户其余字段之前选择用户名和密码。或者,在此页面上,您可以选择一个用户名并为用户禁用基于密码的身份验证。

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

仔细考虑如何允许用户管理权限。如果您赋予非超级用户编辑用户的权限,这最终等同于赋予他们超级用户权限,因为他们将能够提升包括他们自己的用户的权限!

更改密码

用户密码不会显示在管理员中(也不会存储在数据库中),但是会显示 密码存储详情。此信息显示中包含指向密码更改表单的链接,允许管理员更改或取消设置用户密码。

返回顶部