Skip to main content

使用Django认证系统

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

Django认证一起提供认证和授权,并且通常被称为认证系统,因为这些特征有点耦合。

User 对象

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

默认用户的主要属性是:

请参阅 full API documentation 以供参考,后面的文档更加面向任务。

创建用户

创建用户的最直接的方法是使用包含的 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管理员,你也可以 以交互方式创建用户

创建超级用户

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

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

系统将提示您输入密码。输入之后,将立即创建用户。如果您离开 --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(**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

注解

这是一种认证一组凭证的低级方法;例如,它被 RemoteUserMiddleware 使用。除非你正在编写自己的认证系统,否则你可能不会使用它。相反,如果您正在寻找一种方法来限制对登录用户的访问,请参阅 login_required() 装饰器。

权限和授权

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

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

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

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

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

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

权限不仅可以针对每个对象类型设置,还可以针对每个特定的对象实例设置。通过使用 ModelAdmin 类提供的 has_add_permission()has_change_permission()has_delete_permission() 方法,可以为同一类型的不同对象实例定制权限。

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_label foo 和名为 Bar 的模型的应用程序,要测试基本权限,您应该使用:

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

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

  • 删除:user.has_perm('foo.delete_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

权限缓存

ModelBackend 在首次访问用户对象以获取权限检查时缓存其权限。这通常适用于请求 - 响应周期,因为通常在添加(例如,在管理员中)之后不立即检查权限。如果您添加权限并在之后立即检查它们,则在测试或视图中,最简单的解决方案是从数据库重新获取用户。例如:

from django.contrib.auth.models import Permission, User
from django.shortcuts import get_object_or_404

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_bar')

    permission = Permission.objects.get(codename='change_bar')
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm('myapp.change_bar')  # 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_bar')  # True

    ...

Web请求中的身份验证

Django使用 会话 和中间件将认证系统挂接到 request objects 中。

它们在代表当前用户的每个请求上提供 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() 使用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(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 1.10:

在旧版本中,当您手动记录用户时,您在呼叫 login() 之前,must 已成功使用 authenticate() 验证用户。现在,您可以使用新的 backend 参数设置后端。

选择身份验证后端

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

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

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

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

  4. 否则,引发异常。

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

如何记录用户

logout(request)

要注销已通过 django.contrib.auth.login() 登录的用户,请在视图中使用 django.contrib.auth.logout()。它需要一个 HttpRequest 对象,并且没有返回值。例:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

请注意,如果用户未登录,logout() 不会抛出任何错误。

当您调用 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() 执行以下操作:

  • 如果用户未登录,请重定向到 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

url(r'^accounts/login/$', auth_views.login),

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

注解

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

参见

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

LoginRequired 混音

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

class LoginRequiredMixin
New in Django 1.9.

如果视图正在使用此混合,未经身份验证的用户的所有请求将被重定向到登录页面或显示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 装饰器一样,此混合器不检查用户上的 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
New in Django 1.9.

当使用 基于类的视图 时,您可以使用 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.can_vote')
def my_view(request):
    ...

has_perm() 方法一样,权限名称采用 "<app label>.<permission codename>" 格式(即 polls 应用程序中模型上的许可权的 polls.can_vote)。

装饰器也可以采用可迭代的权限,在这种情况下,用户必须具有所有权限才能访问视图。

注意,permission_required() 还采用可选的 login_url 参数:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', 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.can_vote', raise_exception=True)
def my_view(request):
    ...
Changed in Django 1.9:

在旧版本中,permission 参数只处理字符串,列表和元组,而不是字符串和任何可迭代。

PermissionRequiredMixin 混音

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

class PermissionRequiredMixin
New in Django 1.9.

这个混合,就像 permission_required 装饰器一样,检查访问视图的用户是否具有所有给定的权限。您应该使用 permission_required 参数指定权限(或权限的可迭代):

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'polls.can_vote'
    # Or multiple of permissions:
    permission_required = ('polls.can_open', 'polls.can_edit')

您可以设置 AccessMixin 的任何参数以自定义未授权用户的处理。

您还可以覆盖这些方法:

get_permission_required()

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

has_permission()

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

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

为了简化在 基于类的视图 中的访问限制的处理,AccessMixin 可以用于将用户重定向到登录页面或发出HTTP 403禁止响应。

class AccessMixin
New in Django 1.9.
login_url

get_login_url() 的默认返回值。默认为 None,在这种情况下 get_login_url() 回退到 settings.LOGIN_URL

permission_denied_message

get_permission_denied_message() 的默认返回值。默认为空字符串。

redirect_field_name

get_redirect_field_name() 的默认返回值。默认为 "next"

raise_exception

如果此属性设置为 True,将引发 PermissionDenied 异常而不是重定向。默认为 False

get_login_url()

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

get_permission_denied_message()

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

get_redirect_field_name()

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

handle_no_permission()

根据 raise_exception 的值,该方法会引发 PermissionDenied 异常或将用户重定向到 login_url,如果设置,则可选地包括 redirect_field_name

密码更改时会话无效

Changed in Django 1.10:

会话验证已启用,并且在Django 1.10中是强制的(无法禁用它),无论是否启用了 SessionAuthenticationMiddleware。在旧版本中,此保护仅适用于在 MIDDLEWARE 中启用了 django.contrib.auth.middleware.SessionAuthenticationMiddleware 的情况。

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

django.contrib.auth 管理员中的Django,password_change()user_change_password 视图包含的默认密码更改视图使用新密码哈希更新会话,以便用户更改自己的密码不会自行登出。如果您有自定义密码更改视图并希望具有类似的行为,请使用 update_session_auth_hash() 功能。然而,在这种情况下,如果用户还希望使他们更改密码的会话无效(例如,如果他们认为他们的计算机上的会话cookie被盗),那么他们也需要注销该会话。

update_session_auth_hash(request, user)

此函数接受当前请求和更新的用户对象,从中导出新的会话哈希,并适当地更新会话哈希。用法示例:

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() 是基于 SECRET_KEY,更新您的网站以使用新的密钥将使所有现有会话无效。

认证视图

Django提供了几个视图,您可以使用它们来处理登录,注销和密码管理。这些使用 股票auth形式,但你也可以传递自己的形式,以及。

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

使用视图

在项目中实现这些视图有不同的方法。最简单的方法是将提供的URLconf包含在您自己的URLconf中的 django.contrib.auth.urls 中:

urlpatterns = [
    url('^', include('django.contrib.auth.urls')),
]

这将包括以下网址格式:

^login/$ [name='login']
^logout/$ [name='logout']
^password_change/$ [name='password_change']
^password_change/done/$ [name='password_change_done']
^password_reset/$ [name='password_reset']
^password_reset/done/$ [name='password_reset_done']
^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$ [name='password_reset_confirm']
^reset/done/$ [name='password_reset_complete']

视图提供了一个URL名称,以方便参考。有关使用命名网址格式的详细信息,请参阅 URL文档

如果您想要更多地控制网址,可以在URLconf中引用特定视图:

from django.contrib.auth import views as auth_views

urlpatterns = [
    url('^change-password/$', auth_views.password_change),
]

视图具有可选参数,可用于更改视图的行为。例如,如果要更改视图使用的模板名称,您可以提供 template_name 参数。一种方法是在URLconf中提供关键字参数,这些将被传递给视图。例如:

urlpatterns = [
    url(
        '^change-password/$',
        auth_views.password_change,
        {'template_name': 'change-password.html'}
    ),
]

所有视图返回一个 TemplateResponse 实例,允许您在渲染之前轻松自定义响应数据。一种方法是在你自己的视图中包装一个视图:

from django.contrib.auth import views

def change_password(request):
    template_response = views.password_change(request)
    # Do something with `template_response`
    return template_response

有关更多详情,请参阅 TemplateResponse文档

所有认证视图

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

login(request, template_name=`registration/login.html`, redirect_field_name='next', authentication_form=AuthenticationForm, current_app=None, extra_context=None, redirect_authenticated_user=False)

网址名称: login

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

可选参数:

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

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

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

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

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

    警告

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

New in Django 1.10:

添加了 redirect_authenticated_user 参数。

这里是 django.contrib.auth.views.login 做的:

  • 如果通过 GET 调用,它显示POST到同一URL的登录表单。更多关于这一点。

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

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

  • form:表示 AuthenticationFormForm 对象。

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

  • site:当前 Site,根据 SITE_ID 设置。如果您没有安装网站框架,这将被设置为 RequestSite 的实例,该实例从当前 HttpRequest 派生站点名称和域。

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

如果你不想调用模板 registration/login.html,你可以通过额外的参数传递 template_name 参数到URLconf中的视图。例如,此URLconf行将使用 myapp/login.html:

url(r'^accounts/login/$', auth_views.login, {'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() 方法(此方法仅在成功验证表单后调用)。

logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name='next', current_app=None, extra_context=None)

记录用户。

网址名称: logout

可选参数:

  • next_page:注销后重定向到的URL。如果未提供,则默认为 settings.LOGOUT_REDIRECT_URL

  • template_name:在记录用户之后显示的模板的全名。如果未提供参数,则默认为 registration/logged_out.html

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

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

模板上下文:

  • title:本地化的字符串“Logged out”。

  • site:当前 Site,根据 SITE_ID 设置。如果您没有安装网站框架,这将被设置为 RequestSite 的实例,该实例从当前 HttpRequest 派生站点名称和域。

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

logout_then_login(request, login_url=None, current_app=None, extra_context=None)

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

网址名称: 未提供默认URL

可选参数:

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

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

password_change(request, template_name='registration/password_change_form.html', post_change_redirect=None, password_change_form=PasswordChangeForm, current_app=None, extra_context=None)

允许用户更改其密码。

网址名称: password_change

可选参数:

  • template_name:用于显示密码更改表单的模板的全名。如果未提供,则默认为 registration/password_change_form.html

  • post_change_redirect:成功更改密码后重定向的URL。

  • password_change_form:必须接受 user 关键字参数的自定义“更改密码”表单。该表单负责实际更改用户的密码。默认为 PasswordChangeForm

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

模板上下文:

  • form:密码更改表(见上面的 password_change_form)。

password_change_done(request, template_name='registration/password_change_done.html', current_app=None, extra_context=None)

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

网址名称: password_change_done

可选参数:

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

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

password_reset(request, template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html', subject_template_name='registration/password_reset_subject.txt', password_reset_form=PasswordResetForm, token_generator=default_token_generator, post_reset_redirect=None, from_email=None, current_app=None, extra_context=None, html_email_template_name=None, extra_email_context=None)

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

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

用户被标记为不可用的密码(请参阅 set_unusable_password() 不允许请求重置密码以防止在使用LDAP等外部认证源时发生误操作)。注意,他们不会收到任何错误消息,因为这将暴露其帐户的存在,但没有邮件也将被发送。

网址名称: password_reset

可选参数:

  • template_name:用于显示密码重置表单的模板的全名。如果未提供,则默认为 registration/password_reset_form.html

  • email_template_name:用于使用重置密码链接生成电子邮件的模板的全名。如果未提供,则默认为 registration/password_reset_email.html

  • subject_template_name:用于具有重置密码链接的电子邮件主题的模板的全名。如果未提供,则默认为 registration/password_reset_subject.txt

  • password_reset_form:用于获取用户重置密码的电子邮件的表单。默认为 PasswordResetForm

  • token_generator:类的实例检查一次性链接。这将默认为 default_token_generator,它是 django.contrib.auth.tokens.PasswordResetTokenGenerator 的实例。

  • post_reset_redirect:成功重置密码后重定向到的网址。

  • from_email:有效的电子邮件地址。默认情况下,Django使用 DEFAULT_FROM_EMAIL

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

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

  • extra_email_context:电子邮件模板中将提供的上下文数据字典。

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

New in Django 1.9:

添加了 extra_email_context 参数。

模板上下文:

  • form:用于重置用户密码的表单(请参阅上面的 password_reset_form)。

电子邮件模板上下文:

  • emailuser.email 的别名

  • user:当前 User,根据 email 表单字段。只有活动用户才能重置其密码(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 %}

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

password_reset_done(request, template_name='registration/password_reset_done.html', current_app=None, extra_context=None)

在用户已通过电子邮件发送重置密码的链接后显示的页面。如果 password_reset() 视图没有设置显式 post_reset_redirect URL,则默认调用此视图。

网址名称: password_reset_done

注解

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

可选参数:

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

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

password_reset_confirm(request, uidb64=None, token=None, template_name='registration/password_reset_confirm.html', token_generator=default_token_generator, set_password_form=SetPasswordForm, post_reset_redirect=None, current_app=None, extra_context=None)

提供用于输入新密码的表单。

网址名称: password_reset_confirm

可选参数:

  • uidb64:以64位编码的用户ID。默认为 None

  • token:检查密码有效的令牌。默认为 None

  • template_name:用于显示确认密码视图的模板的全名。默认值为 registration/password_reset_confirm.html

  • token_generator:检查密码的类的实例。这将默认为 default_token_generator,它是 django.contrib.auth.tokens.PasswordResetTokenGenerator 的实例。

  • set_password_form:将用于设置密码的表单。默认为 SetPasswordForm

  • post_reset_redirect:重置密码后重定向的网址。默认为 None

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

模板上下文:

  • form:用于设置新用户密码的格式(参见上面的 set_password_form)。

  • validlink:Boolean,如果链接(uidb64token 的组合)有效或未使用,则为True。

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

password_reset_complete(request, template_name='registration/password_reset_complete.html', current_app=None, extra_context=None)

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

网址名称: password_reset_complete

可选参数:

  • template_name:用于显示视图的模板的全名。默认为 registration/password_reset_complete.html

  • current_app:指示哪个应用程序包含当前视图的提示。有关详细信息,请参阅 命名空间的URL解析策略

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

1.9 版后已移除: current_app 参数已弃用,将在Django 2.0中删除。来电者应该设置 request.current_app

帮助函数

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 forms.ValidationError(
                _("This account is inactive."),
                code='inactive',
            )
        if user.username.startswith('b'):
            raise forms.ValidationError(
                _("Sorry, accounts starting with 'b' aren't welcome here."),
                code='no_b_users',
            )
class PasswordChangeForm

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

class PasswordResetForm

用于生成并通过电子邮件发送一次性使用链接以重置用户密码的表单。

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

class SetPasswordForm

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

class UserChangeForm

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

class UserCreationForm

用于创建新用户的 ModelForm

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

模板中的认证数据

当您使用 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 应用程序中有任何权限,此示例将显示 True:

{{ perms.foo }}

两级属性查找是 User.has_perm 的代理。如果登录的用户具有 foo.can_vote 权限,则此示例将显示 True:

{{ perms.foo.can_vote }}

因此,您可以在模板 {% if %} 语句中检查权限:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.can_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.can_drive %}
        <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.can_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}

在管理员中管理用户

当您同时安装了 django.contrib.admindjango.contrib.auth 时,管理员提供了一种方便的方式来查看和管理用户,组和权限。可以像任何Django模型一样创建和删除用户。可以创建组,并且可以将权限分配给用户或组。还存储和显示用户对在管理员内进行的模型进行编辑的日志。

创建用户

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

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

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

更改密码

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