使用 Django 认证系统

本文档解释了Django的身份验证系统在其默认配置中的用法。这种配置已经发展为服务于最常见的项目需求,处理相当广泛的任务,并具有密码和权限的仔细实现。对于认证需求不同于默认值的项目,Django支持广泛的 extension and customization 身份验证。

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

User 对象

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

默认用户的主要属性是:

full API documentation 为了充分参考,下面的文档更加面向任务。

创建用户

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

>>> 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管理员,也可以 create users interactively .

创建超级用户

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

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

系统将提示您输入密码。输入一个后,将立即创建用户。如果你离开 --username--email 选项,它将提示您输入这些值。

更改密码

Django不在用户模型上存储原始(明文)密码,而只存储哈希(请参见 documentation of how passwords are managed 详细信息)。因此,不要试图直接操作用户的密码属性。这就是在创建用户时使用助手函数的原因。

要更改用户密码,您有几个选项:

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

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

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

如果安装了django admin,还可以在 authentication system's admin pages .

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

更改用户密码将注销其所有会话。见 密码更改时会话无效 有关详细信息。

正在验证用户

authenticate(request=None, **credentials)[源代码]
aauthenticate(request=None, **credentials)[源代码]

Asynchronous versionaauthenticate()

使用 authenticate() 验证一组凭据。它将凭证作为关键字参数, usernamepassword 对于默认情况,将它们与 authentication backend 并返回一个 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 .

Changed in Django 5.0:

aauthenticate() 添加了功能。

许可和授权

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

它被django管理网站使用,但欢迎您在自己的代码中使用它。

django管理站点使用以下权限:

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

  • 查看“添加”表单和添加对象的权限仅限于对该类型对象具有“添加”权限的用户。

  • 查看更改列表、查看“更改”窗体和更改对象的权限仅限于对该类型对象具有“更改”权限的用户。

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

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

User 对象有两个多对多字段: groupsuser_permissions . User 对象可以以与任何其他对象相同的方式访问其相关对象 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()

默认权限

什么时候? django.contrib.auth 列在您的 INSTALLED_APPS 设置时,它将确保为在某个已安装的应用程序中定义的每个Django模型创建四个默认权限(添加、更改、删除和查看)。

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

假设您有一个应用程序 app_label foo 还有一个叫 Bar ,若要测试基本权限,应使用:

  • 添加: user.has_perm('foo.add_bar')

  • 变化: user.has_perm('foo.change_bar')

  • 删除: user.has_perm('foo.delete_bar')

  • 观点: user.has_perm('foo.view_bar')

这个 Permission 很少直接访问模型。

django.contrib.auth.models.Group 模型是对用户进行分类的通用方法,因此您可以对这些用户应用权限或其他标签。用户可以属于任意数量的组。

组中的用户自动拥有授予该组的权限。例如,如果 Site editors 得到许可 can_edit_home_page ,该组中的任何用户都将具有该权限。

除了权限之外,组还可以方便地对用户进行分类,为他们提供一些标签或扩展功能。例如,可以创建一个组 'Special users' 您可以编写代码,例如,允许他们访问您站点中仅限成员的部分,或者向他们发送仅限成员的电子邮件。

以编程方式创建权限

同时 custom permissions 可以在模型中定义 Meta 类,还可以直接创建权限。例如,可以创建 can_publish 许可 BlogPost 模型在 myapp ::

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
    codename="can_publish",
    name="Can Publish Posts",
    content_type=content_type,
)

然后可以将权限分配给 User 通过其 user_permissions 属性或到 Group 通过其 permissions 属性。

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

如果要创建 permissions for a proxy model 通过 for_concrete_model=FalseContentTypeManager.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使用 sessions 以及连接认证系统的中间件 request objects .

这些功能提供了一种 request.user 属性和一个 request.auser 对表示当前用户的每个请求使用Async方法。如果当前用户尚未登录,则此属性将设置为 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.
    ...
Changed in Django 5.0:

这个 HttpRequest.auser() 添加了方法。

如何登录用户

如果您有一个经过身份验证的用户要附加到当前会话-这是通过 login() 功能。

login(request, user, backend=None)[源代码]
alogin(request, user, backend=None)[源代码]

Asynchronous versionalogin()

要从视图登录用户,请使用 login() . 它需要一个 HttpRequest 对象与A 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.
        ...
Changed in Django 5.0:

alogin() 添加了功能。

选择身份验证后端

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

  1. 使用选项的值 backend 参数(如果提供)。

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

  3. 使用 backend 在里面 AUTHENTICATION_BACKENDS ,如果只有一个。

  4. 否则,引发异常。

在案例1和案例2中, backend 论证或 user.backend 属性应为点式导入路径字符串(如 AUTHENTICATION_BACKENDS )不是实际的后端类。

如何注销用户

logout(request)[源代码]
alogout(request)[源代码]

Asynchronous versionalogout()

注销通过登录的用户 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()

Changed in 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 并且您的登录视图是正确关联的。例如,使用默认值,将以下行添加到您的urlconf::

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 混合

使用时 class-based views ,您可以实现与 login_required 通过使用 LoginRequiredMixin . 这个mixin应该在继承列表中最左边的位置。

class LoginRequiredMixin

如果视图正在使用此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 装饰工,这个混音器不检查 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 当可调用返回时执行重定向的decorator 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

使用时 class-based views ,您可以使用 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 应用程序)。

修饰器也可以接受ITable的权限,在这种情况下,用户必须拥有所有的权限才能访问视图。

注意 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 提示 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):
    ...

这也避免了在 LoginViewredirect_authenticated_user=True 登录的用户没有所有必需的权限。

这个 PermissionRequiredMixin 混合类型

将权限检查应用于 class-based views ,您可以使用 PermissionRequiredMixin

class PermissionRequiredMixin

这个混音,就像 permission_required decorator,检查访问视图的用户是否具有所有给定的权限。您应该使用 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使用的权限名的iteable。默认为 permission_required 属性,必要时转换为元组。

has_permission()

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

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

以简化对访问限制的处理 class-based views , the AccessMixin 可用于配置拒绝访问时视图的行为。通过身份验证的用户被拒绝访问HTTP 403禁止响应。匿名用户被重定向到登录页面或显示HTTP 403禁止响应,具体取决于 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 ,A PermissionDenied 条件不满足时引发异常。什么时候? False (默认),匿名用户被重定向到登录页面。

get_login_url()

返回未通过测试的用户将被重定向到的URL。退换商品 login_url 如果设置,或 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 如果它被设置了。

密码更改时会话无效

如果你 AUTH_USER_MODEL 继承自 AbstractBaseUser 或实现自己的 get_session_auth_hash() 方法,经过身份验证的会话将包括此函数返回的哈希。在 AbstractBaseUser 案例,这是密码字段的HMAC。Django验证会话中每个请求的散列是否与请求期间计算的散列相匹配。这允许用户通过更改密码注销所有会话。

Django附带的默认密码更改视图, PasswordChangeView 以及 user_change_password 视图中 django.contrib.auth 管理员,用新密码散列更新会话,这样用户更改自己的密码就不会注销自己。如果您有自定义的密码更改视图,并且希望具有类似的行为,请使用 update_session_auth_hash() 功能。

update_session_auth_hash(request, user)[源代码]
aupdate_session_auth_hash(request, user)[源代码]

Asynchronous versionaupdate_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:
        ...
Changed in Django 5.0:

aupdate_session_auth_hash() 添加了功能。

备注

自.以来 get_session_auth_hash() 是基于 SECRET_KEY ,在更新站点以使用新密钥时,必须轮换密钥值以避免使现有会话无效。看见 SECRET_KEY_FALLBACKS 了解更多细节。

身份验证视图

Django提供了几个视图,可用于处理登录、注销和密码管理。它们利用了 stock auth forms 但你也可以通过你自己的形式。

Django没有为身份验证视图提供默认模板。您应该为要使用的视图创建自己的模板。模板上下文记录在每个视图中,请参见 所有身份验证视图 .

使用视图

在项目中实现这些视图有不同的方法。最简单的方法是在 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名称以便于参考。见 the URL documentation 有关使用命名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"),
    ),
]

所有视图都是 class-based ,这允许您通过子类化轻松地自定义它们。

所有身份验证视图

这是包含所有视图的列表 django.contrib.auth 提供。有关实现的详细信息,请参阅 使用视图 .

class LoginView

网址名称: login

the URL documentation 有关使用命名URL模式的详细信息。

Methods and Attributes

template_name

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

next_page

登录后要重定向到的URL。默认为 LOGIN_REDIRECT_URL

redirect_field_name

对象的名称 GET 包含登录后要重定向到的URL的字段。默认为 next 。重写 get_default_redirect_url() URL,如果给定的 GET 参数被传递。

authentication_form

用于身份验证的可调用对象(通常为Form类)。默认为 AuthenticationForm

extra_context

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

redirect_authenticated_user

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

警告

如果启用 redirect_authenticated_user ,其他网站可以通过请求将URL重定向到您网站上的图像文件来确定他们的访问者是否在您的网站上通过了身份验证。要避免“社交媒体指纹识别”,请在单独的域中承载所有图像和您的Favicon。

有可能 redirect_authenticated_user 当使用 permission_required() 除非 raise_exception 使用了参数。

success_url_allowed_hosts

A set 主机的数量,除了 request.get_host() ,登录后重定向是安全的。缺省值为空 set

get_default_redirect_url()

返回登录后要重定向到的URL。默认实现解析并返回 next_page 如果设置,则返回或 LOGIN_REDIRECT_URL 否则的话。

这里是什么 LoginView 做:

  • 如果被调用通过 GET ,它显示一个发布到同一URL的登录表单。这方面的更多信息。

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

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

如果您不想调用模板 registration/login.html ,您可以通过 template_name 参数通过 as_view 方法。例如,此urlconf行将使用 myapp/login.html 取而代之的是:

path("accounts/login/", auth_views.LoginView.as_view(template_name="myapp/login.html")),

还可以指定 GET 字段,其中包含登录后使用 redirect_field_name . 默认情况下,该字段被调用 next .

这是一个样本 registration/login.html 模板可以用作起点。它假设你有一个 base.html 定义一个 content

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>

{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

如果您已自定义身份验证(请参见 Customizing Authentication )您可以通过设置 authentication_form 属性。此表单必须接受 request 其中的关键字参数 __init__() 方法和提供 get_user() 返回经过身份验证的用户对象的方法(只有在成功的表单验证之后才调用此方法)。

class LogoutView

将用户注销到 POST 请求。

网址名称: logout

属性:

next_page

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

template_name

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

redirect_field_name

对象的名称 GET 包含注销后要重定向到的URL的字段。默认为 'next' 。重写 next_page URL,如果给定的 GET 参数被传递。

extra_context

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

success_url_allowed_hosts

A set 主机的数量,除了 request.get_host() ,在注销后重定向是安全的。缺省值为空 set

模板上下文:

logout_then_login(request, login_url=None)

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

网址名称: 未提供默认URL

可选参数:

  • login_url :要重定向到的登录页的URL。默认为 settings.LOGIN_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

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

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

  • 系统中存在提供的电子邮件地址。

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

  • 请求的用户具有可用的密码。标记有不可用密码的用户(请参见 set_unusable_password() )不允许请求密码重置,以防止在使用外部身份验证源(如ldap)时被滥用。

如果这些条件中的任何一个是 not 则不会发送电子邮件,但用户也不会收到任何错误消息。这可以防止信息泄露给潜在的攻击者。如果您想在这种情况下提供错误消息,您可以子类 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: An alias for user.email

  • user 当前 User ,根据 email 表单字段。只有活动用户才能重置其密码 (User.is_active is True

  • site_name 一个别名 site.name . 如果没有安装站点框架,则将其设置为 request.META['SERVER_NAME'] . 有关网站的更多信息,请参阅 “站点”框架 .

  • domain 一个别名 site.domain . 如果没有安装站点框架,则将其设置为 request.get_host() .

  • protocol HTTP或HTTPS

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

  • token :检查重置链接是否有效的令牌。

样品 registration/password_reset_email.html (电子邮件正文模板):

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

相同的模板上下文用于主题模板。主题必须是单行纯文本字符串。

class PasswordResetDoneView

网址名称: 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 。仅当您有多个 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。默认为 settings.LOGIN_URL 如果未提供。

  • redirect_field_name A的名字 GET 包含注销后要重定向到的URL的字段。重写 next 如果给定 GET 参数已传递。

内置窗体

如果您不想使用内置视图,但希望不必为此功能编写表单,则身份验证系统将提供位于 django.contrib.auth.forms

备注

内置的身份验证表单对他们使用的用户模型做了某些假设。如果你用的是 custom user model ,可能需要为身份验证系统定义自己的表单。有关详细信息,请参阅有关 using the built-in authentication forms with custom user models .

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() 填充 context 有相同的变量 PasswordResetView 传递到其电子邮件上下文。

class SetPasswordForm

允许用户在不输入旧密码的情况下更改密码的表单。

class UserChangeForm

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

class BaseUserCreationForm

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

它有三个字段: username (来自用户模型) password1password2 . 它证实了 password1password2 匹配,使用验证密码 validate_password() ,并使用 set_password() .

class UserCreationForm

继承自 BaseUserCreationForm 。为了避免与相似的用户名混淆,表单不允许仅大小写不同的用户名。

模板中的身份验证数据

当前登录的用户及其权限在 template context 当你使用 RequestContext .

技术性

从技术上讲,这些变量仅在模板上下文中可用,如果使用 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 ,这是一个模板友好的权限代理。

评估的单属性查找 {{ 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管理站点创建用户,则需要授予他们添加用户的权限。 and 更改用户(即“添加用户”和“更改用户”权限)。如果帐户具有添加用户但不更改用户的权限,则该帐户将无法添加用户。为什么?因为如果您有添加用户的权限,那么您就有权创建超级用户,而超级用户又可以更改其他用户。所以Django需要添加 and 将权限更改为轻微的安全措施。

考虑一下如何允许用户管理权限。如果给非超级用户编辑用户的能力,这最终与给他们超级用户状态相同,因为他们将能够提升用户(包括他们自己)的权限!

更改密码

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