使用Django认证系统

这篇文档解释默认配置下Django认证系统的使用。 这些配置已经逐步可以满足大部分常见项目的需要,可以处理范围非常广泛的任务,且具有一套细致的密码和权限实现。 对于需要与默认配置不同需求的项目,Django支持extension and customization认证。

Django的认证同时提供认证和授权,并通常统一称为认证系统,因为这些功能某些地方是耦合的。

User对象

User对象是认证系统的核心。 它们通常表示与你的站点进行交互的用户,并用于启用限制访问、注册用户信息和给创建者关联内容等。 在Django的认证框架中只存在一种类型的用户,因此诸如'superusers'或管理员'staff'用户只是具有特殊属性集的user对象,而不是不同类型的user对象。

默认user的基本属性有:

完整的参考请参阅full API documentation,以下的内容更偏重特定的任务。

创建用户

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

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

# 到这里,user 这一个User对象已经保存于
# 数据库中了。 # 你可以继续修改它的属性。
# 如果你想要修改其他字段。
>>> user.last_name = 'Lennon'
>>> user.save()

如果你已经安装了Django admin,你也可以create users interactively.

创建超级用户

使用createsuperuser命令创建superusers:

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

将会提示你输入一个密码。 在你输入一个密码后,该user将会立即创建。 如果您离开--username--email选项,它将提示您输入这些值。

更改密码

Django不会在user模型上存储原始的(明文)密码,而只是一个哈希(完整的细节参见documentation of how passwords are managed)。 因为这个原因,不要尝试直接操作user的password属性。 这也是为什么创建一个user时要使用辅助函数。

若要修改一个用户的密码,你有几种选择:

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

你也可以通过程序修改密码,使用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修改user的密码。

Django还提供viewsforms用于允许user修改他们自己密码。

更改用户密码将会注销所有会话。 详细信息请参阅Session invalidation on password change

认证用户

authenticate(request=None, **credentials)[source]

使用authenticate()来验证一组凭据。 它以credentials为关键字参数,默认为usernamepassword,根据每个认证的后端进行检查,如果credentials对某个后端有效则返回一个User对象。 如果credentials对任何后端都无效,或者如果后端引发了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()方法上传递。

在Django 1.11中的更改:

添加了可选的request参数。

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

权限和授权

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

它被Django的admin站点使用,但欢迎你在你自己的代码中使用。

Django admin 站点使用如下的权限:

  • 拥有该类型对象"add"权限的用户才可以访问"add"表单以及添加一个该类型对象。
  • 查看修改列表、查看“change”表单以及修改一个对象的权利只限于具有该类型对象的“change”权限的用户拥有。
  • 用户必须在一个对象上具有“delete”权限,才能删除这个对象。

权限不但可以根据每个对象的类型,而且可以根据特定的对象实例设置。 通过使用ModelAdmin类提供的has_add_permission()has_change_permission()has_delete_permission()方法,可以针对相同类型的不同对象实例自定义权限。

User对象具有两个多对多的字段:groupsuser_permissions User对象可以用和其它Django模型一样的方式访问它们相关联的对象:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

默认权限

django.contrib.auth在你的INSTALLED_APPS设置中列出时,它将确保为你安装的应用中的每个Django模型创建3个默认的权限 – add、change和delete。

当你运行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模型。

Groups

django.contrib.auth.models.Group模型是用户分类的一种通用的方式,通过这种方式你可以应用权限或其它标签到这些用户。 一个用户可以属于任意多个组。

组中某个用户自动具有赋给那个组的权限。 例如,如果组Site editors具有权限 can_edit_home_page,那么该组中的任何用户都具有该权限。

除权限之外,组还是给用户分类的一种方便的方法以给他们某些标签或扩展的功能。 例如,你可以创建一个组'Special users',然后你可以这样写代码,给他们访问你的站点仅限会员的部分,或者给他们发仅限于会员的邮件。

以编程方式创建权限

虽然custom permissions可以定义在模型的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

权限的缓存

在第一次获取权限用于检查后,模型的后端将在该用户对象上缓存这些权限。 这对于常见的请求-响应周期通常没问题,因为通常在添加权限后不会立即检查权限(例如在管理后台中)。 如果你要添加权限并立即检查它们,例如在测试中或视图中,最简单的解决方案是从数据库重新获取用户。 像这样:

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

    ...

Web请求中的认证

Django使用会话和中间件来拦截认证系统到请求对象中。

它们在每个请求上提供一个request.user属性,表示当前的用户。 如果当前的用户没有登入,该属性将设置成AnonymousUser的一个实例,否则它将是User的实例。

你可以使用is_authenticated将它们区分开,如下所示:

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...

如何登录用户

如果你有一个认证了的用户,你想把它附带到当前的会话中 - 这可以通过login()函数完成。

login(request, user, backend=None)[source]

从视图中登入一个用户,请使用login() 它接受一个HttpRequest对象和一个User对象。 login()使用Django的session框架来将用户的ID保存在session中。

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

下面的示例向你演示如何使用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 1.10中的更改:

在旧版本中,当你手工登陆一个用户时,在调用login()之前必须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)[source]

若要登出一个已经通过django.contrib.auth.login()登入的用户,可以在你的视图中使用django.contrib.auth.logout() 它接收一个HttpRequest对象且没有返回值。 例如:

from django.contrib.auth import logout

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

注意,即使用户没有登入,logout()也不会抛出任何错误。

当您调用logout()时,当前请求的会话数据将被彻底清除。 所有存在的数据都将清除。 这是为了防止另外一个人使用相同的Web浏览器登入并访问前一个用户的会话数据。 如果你想在用户登出之后可以立即访问放入会话中的数据,请在调用django.contrib.auth.logout()之后放入。

限制对登录用户的访问

原始方式

限制访问页面的简单原始方法是检查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)[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,你非常可能同时需要自定义你的登录模板,因为存储重定向路径的模板上下文变量将使用"next"值作为它的键,而不是默认的redirect_field_name

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.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()来说是一个有用的替代方法。

LoginRequired mixin

使用class-based views时,可以使用LoginRequiredMixin实现与login_required相同的行为。 此mixin应位于继承列表中最左侧的位置。

class LoginRequiredMixin

如果视图正在使用此mixin,那么根据raise_exception参数,未经身份验证的用户的所有请求将被重定向到登录页面或显示HTTP 403 Forbidden错误。

您可以设置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拒绝不活动的用户。

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

要根据某些权限或某些其他测试来限制访问权限,您可以执行与上一节中所述基本相同的操作。

简单的方法就是在视图中直接运行你对request.user的测试。 例如,视图检查用户的邮件属于特定的地址(例如@example.com),若不是,则重定向到登录页面。

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]

你可以用方便的 False 装饰器,当回调函数返回 user_passes_test 时会执行一个重定向操作:

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
让你指定那些没有通过检查的用户要重定向至哪里。 若不指定其值,它可能是默认的 settings.LOGIN_URL
redirect_field_name
login_required()的参数相同。 把它设置为 None 来把它从 URL 中移除,当你想把通不过检查的用户重定向到没有next page 的非登录页面时。

像这样:

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

检查一个用户是否有指定的权限是相对常见的需求。 为此,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.can_vote表示polls应用中一个模型的权限)。

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

请注意,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):
    ...

PermissionRequiredMixin mixin

要对class-based views应用权限检查,可以使用PermissionRequiredMixin

class PermissionRequiredMixin

这个mixin,就像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()

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

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

为了简化在class-based views中处理访问限制,可以使用AccessMixin将用户重定向到登录页面或发出HTTP 403 Forbidden响应。

class AccessMixin
login_url

Default return value for get_login_url(). 默认为None,在这种情况下,get_login_url()返回到settings.LOGIN_URL

permission_denied_message

Default return value for get_permission_denied_message(). 默认为空字符串。

redirect_field_name

Default return value for get_redirect_field_name(). 默认为"next"

raise_exception

如果此属性设置为True,将会引发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如果设置。

密码更改后的会话失效

在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包含的默认密码修改视图PasswordChangeViewdjango.contrib.auth中的user_change_password视图中,使用新的密码哈希更新会话,以便用户更改自己的密码不会自动登出。 如果你有自定义的密码更改视图并希望具有类似的行为,请使用update_session_auth_hash()函数。

update_session_auth_hash(request, user)[source]

这个函数接受当前请求和更新后的用户对象,获取新的会话哈希并更新会话中的哈希为正确的值。 它还会改变会话的键,以使被盗会话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更改1.11:

添加会话的键的改变。

虽然get_session_auth_hash()基于SECRET_KEY,使用新的私钥升级你的站点会使所有现有会话失效。

认证视图

Django 提供一些视图,你可以用来处理登录、登出和密码管理。 它们使用stock auth forms,但你也可以传递你自己的表单。

Django 没有为认证视图提供默认的模板。 你应该为你想要使用的视图创建自己的模板。 模板的上下文定义在每个视图中,参见All authentication views.

使用视图

有几种不同的方法在你的项目中使用这些视图。 最简单的方法是包含django.contrib.auth.urls 中提供的URLconf到你自己的URLconf中,例如

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

这将包含进下面的URL模式:

^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模式的细节请参见the URL documentation

如果你想更多地控制你的URL,你可以在你的URLconf中引用一个特定的视图:

from django.contrib.auth import views as auth_views

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

这些视图具有可选的参数,你可以用来改变视图的行为。 例如,如果你想修改一个视图使用的模板名称,你可以提供template_name 参数。 一种方法是在URLconf 中提供关键字参数,它们将被传递到视图中。 像这样:

urlpatterns = [
    url(
        '^change-password/$',
        auth_views.PasswordChangeView.as_view(template_name='change-password.html'),
    ),
]

所有视图都是 基于类的, 这允许你很容易通过子类化来定制它们。

所有的认证视图

下面列出了django.contrib.auth提供的所有视图。 实现细节参见Using the views

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

自1.11版以来已弃用 基于函数的login视图应该被基于类的LoginView替代。

该视图的可选参数与基于类的LoginView属性类似。 另外,它有:

自1.9版以来已弃用 current_app属性已弃用,将在Django 2.0中删除。 调用者应该设置request.current_app

Django中的新功能1.10:

添加了redirect_authenticated_user参数。

class LoginView
Django中的新功能1.11。

URL名称: login

使用命名URL模式的细节请参见the URL documentation

属性:

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

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

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

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

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

    警告

    如果您启用了redirect_authenticated_user,其他网站将能够通过请求重定向到网站上的图像文件来确定访问者是否在您的网站上进行身份验证。 To avoid this “social media fingerprinting” information leakage, host all images and your favicon on a separate domain.

  • success_url_allowed_hosts:一个主机名的set(集合),除了request.get_host()之外,可以在登录后安全地重定向到它们。 默认为空set

这是LoginView所做的事情:

  • 如果通过 GET调用,它显示一个POST给相同URL的登录表单。 后面有更多这方面的信息。
  • 如果通过POST调用并带有用户提交的凭证,它会尝试登入该用户。 如果登入成功,该视图重定向到next中指定的URL。 如果未提供next,则会重定向到settings.LOGIN_REDIRECT_URL(默认为/accounts/profile/)。 如果登入不成功,则重新显示登录表单。

你需要提供html模板给login,默认调用registration/login.html 模板会得到4个模板上下文变量:

如果您不想调用模板registration/login.html,您可以通过额外的参数将template_name参数传递给as_view你的URLconf中的方法。 例如,下面URLconf中的行将使用myapp/login.html

url(r'^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 setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

如果您有自定义身份验证(请参阅Customizing Authentication),您可以通过设置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)

自1.11版以来已弃用 基于函数的logout视图应该被基于类的LogoutView替代。

该视图的可选参数类似于基于类的LogoutView属性。 另外,它有:

自1.9版以来已弃用 current_app属性已弃用,将在Django 2.0中删除。 调用者应该设置request.current_app替代。

class LogoutView
Django中的新功能1.11。

登出一个用户。

URL名称: logout

属性:

  • next_page:注销后重定向到的URL。 默认为settings.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可以在注销后重定向安全。 默认为空set

模板上下文:

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

登出一个用户,然后重定向到登录页面。

URL名称: 没有提供默认的URL

可选参数:

  • login_url:要重定向到的登录页面的URL。 如果没有提供,默认为settings.LOGIN_URL
  • current_app:指示哪个应用程序包含当前视图的提示。 更多信息参见namespaced URL resolution strategy
  • extra_context:将添加到传递给模板的默认上下文数据的上下文数据字典。

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app替代。

自1.11版以来已弃用 未使用的extra_context参数已被弃用,将在Django 2.1中删除。

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

自1.11版以来已弃用 基于功能的password_change视图应该被基于类的PasswordChangeView替代。

除了post_change_redirectpassword_change_form参数之外,该视图的可选参数类似于基于类的PasswordChangeView属性,它们映射到success_urlform_class属性的基于类的视图。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app替代。

class PasswordChangeView
Django中的新功能1.11。

URL名称: password_change

允许一个用户修改他的密码。

属性:

  • template_name:用于显示密码更改表单的模板的全名。 如果没有提供,默认为registration/password_change_form.html
  • success_url:成功更改密码后重定向到的URL。
  • form_class:需要接受user关键字参数的自定义“更改密码”表单。 表单用于实际修改用户密码。 默认为 PasswordChangeForm
  • extra_context:将添加到传递给模板的默认上下文数据的上下文数据字典。

模板上下文:

  • form:密码更改表单(见上面的form_class)。
password_change_done(request, template_name='registration/password_change_done.html', current_app=None, extra_context=None)

自1.11版以来已弃用 基于函数的password_change_done视图应该被基于类的PasswordChangeDoneView替代。

此视图的可选参数与基于类的PasswordChangeDoneView属性类似。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app替代。

class PasswordChangeDoneView
Django中的新功能1.11。

URL名称: password_change_done

这个页面在用户修改密码之后显示。

属性:

  • template_name:要使用的模板的全名。 如果没有提供,默认为registration/password_change_done.html
  • extra_context:将添加到传递给模板的默认上下文数据的上下文数据字典。
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)

自1.11版以来已弃用 基于功能的password_reset视图应该被基于类的PasswordResetView替代。

这个视图的可选参数,都类似于基于类的PasswordResetView 的属性, 除了 the post_reset_redirectpassword_reset_form 参数,这些参数映射基于类的视图的success_urlform_class 属性。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app

class PasswordResetView
Django中的新功能1.11。

网址名称: password_reset

允许用户通过生成一次性的连接并发送到用户注册的邮箱地址中来重置密码。

如果提供的邮箱地址不在系统中存在,这个视图不会发送任何邮件,但是用户也不会收到任何错误信息。 这会阻止数据泄露给潜在的攻击者。 如果要在这种情况下提供错误消息,您可以继承PasswordResetForm并使用form_class属性。

用无效密码标记的用户(参见set_unusable_password())不允许请求重置密码,为了防止使用类似于LDAP的外部验证资源时的滥用。 注意它们不会收到任何错误信息,因为这会暴露它们的账户,也不会发送任何邮件。

属性:

  • template_name:用于显示密码重置表单的模板的全名。 如果不提供,则默认为registration/password_reset_form.html
  • form_class:用于获取用户重置密码的电子邮件的表单。 默认为PasswordResetForm
  • email_template_name:用于使用重置密码链接生成电子邮件的模板的全名。 如果不提供,则默认为registration/password_reset_email.html
  • subject_template_name:用于使用重置密码链接的电子邮件主题的模板的全名。 如果不提供,则默认为registration/password_reset_subject.txt
  • token_generator:类的实例检查一次性链接。 默认为django.contrib.auth.tokens.PasswordResetTokenGenerator,它是 default_token_generator 的一个实例。
  • success_url:在成功的密码重置请求后重定向到的URL。
  • from_email:有效的电子邮件地址。 默认情况下Django 使用DEFAULT_FROM_EMAIL
  • extra_context:将添加到传递给模板的默认上下文数据的上下文数据字典。
  • html_email_template_name:用于生成具有密码重置链接的text/html多部分电子邮件的模板的全名。 默认情况下,不发送HTML电子邮件。
  • extra_email_context:将在电子邮件模板中可用的上下文数据字典。

模板上下文:

  • form:用于重置用户密码的窗体(见form_class)。

邮件模板上下文:

  • emailuser.email的别名
  • user:根据email表单字段,当前User 只有有效用户才能重置其密码(User.is_active True)。
  • site_namesite.name的别名。 如果你没有安装site框架,这将被设置成request.META['SERVER_NAME']的值。 关于site 的更多信息,参见The “sites” framework
  • domainsite.domain的别名。 如果您没有安装网站框架,则会将其设置为request.get_host()的值。
  • protocol:http或https
  • uid:用户的主键编码在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 %}

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

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

自1.11版以来已弃用 基于功能的password_reset_done视图应该被基于类的PasswordResetDoneView替代。

此视图的可选参数类似于基于类的PasswordResetDoneView属性。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app

class PasswordResetDoneView
Django中的新功能1.11。

网址名称: password_reset_done

这个页面在向用户发送重置密码的邮件后展示。 如果PasswordResetView没有明确的success_url URL设置,默认情况下会调用此视图。

如果提供的email地址在系统中不存在,用户未激活,或者密码不可用,用户仍然会重定向到这个视图,但是不会发送邮件。

属性:

  • template_name:要使用的模板的全名。 如果未提供,默认为registration/password_reset_done.html
  • extra_context:将添加到传递给模板的默认上下文数据的上下文数据字典。
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)

自1.11版以来已弃用 基于功能的password_reset_confirm视图应该由基于类的PasswordResetConfirmView代替。

该视图的可选参数与基于类的PasswordResetConfirmView属性类似,除了post_reset_redirectset_password_form参数,它们映射到success_urlform_class属性的基于类的视图。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app

class PasswordResetConfirmView
Django中的新功能1.11。

URL名称: password_reset_confirm

为输入新密码展示表单。

网址的关键字参数:

  • uidb64:用户的ID编码在64位。
  • token:令牌来检查密码是否有效。

属性:

  • template_name:显示确认密码视图的模板的全名。 默认值为registration/password_reset_confirm.html
  • token_generator:检查密码的类的实例。 默认为django.contrib.auth.tokens.PasswordResetTokenGenerator,它是 default_token_generator 的一个实例。
  • 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:将添加到传递给模板的默认上下文数据的上下文数据字典。

模板上下文:

  • form:用于设置新用户密码的窗体(见set_password_form)。
  • validlink:Boolean,如果链接(uidb64token的组合)有效或未使用,则为True。
password_reset_complete(request, template_name='registration/password_reset_complete.html', current_app=None, extra_context=None)

自1.11版以来已弃用 基于功能的password_reset_complete视图应该被基于类的PasswordResetCompleteView替代。

该视图的可选参数类似于基于类的PasswordResetCompleteView属性。 另外,它有:

自1.9版以来已弃用 current_app参数已被弃用,将在Django 2.0中删除。 调用者应该设置request.current_app

class PasswordResetCompleteView
Django中的新功能1.11。

网址名称: 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:包含要注销后重定向到的URL的GET字段的名称。 如果传递给定的GET参数,则覆盖next

内置表单

如果你不想用内建的视图,但是又不想编写针对该功能的表单,认证系统提供了几个内建的表单,位于django.contrib.auth.forms

内建的验证表单对它们处理的用户模型做了特定假设。 如果您使用custom user model,则可能需要为身份验证系统定义自己的表单。 更多信息请见using the built-in authentication forms with custom user models的文档。

class AdminPasswordChangeForm

Admin 站点中使用的表单,用于修改用户密码。

接受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.用户名.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_templateNonehtml_email_template 的上下文(如果它不为email_template)。
  • from_email —— 发信人的地址。
  • to_email —— 收件人的地址。
  • html_email_template_name —— HTML 格式的邮件正文的模板;默认为None,这种情况下将发送纯文本文件。

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

class SetPasswordForm

允许用户不输入旧密码修改密码的表单。

class UserChangeForm

Admin 站点中使用的表单,用于修改用户信息和权限。

class UserCreationForm

用于创建新用户的ModelForm

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

模板中的验证数据

当你使用RequestContext时,当前登入的用户和它们的权限在template context中可以访问。

技术细节

技术上讲,这些变量只有在你使用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,则不可以访问该模板变量:

权限¶ T0>

当前登录的用户的权限存储在模板变量{{ 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.authdjango.contrib.admin这两个你都安装了,将可以通过admin方便地查看和管理用户、组和权限。 可以像其它任何Django模型一样创建和删除用户。 可以创建组,并分配权限给用户和组。 admin中还会保存和显示对用户模型编辑的日志。

创建用户

在admin的主页,你应该可以在“Auth”部分看到“Users”链接。 “Add user” 页面与标准admin页面不同点在于它要求你在编辑用户的其它字段之前先选择一个用户名和密码。

另请注意:如果你想使得一个用户能够使用Django的admin站点创建其它用户, 你需要给他添加用户修改用户的权限(例如,"Add user” 和“Change user” 权限)。 如果一个账号具有添加用户的权限但是没有权限修改他们,该账号将不能添加用户。 为什么呢? 因为如果你具有添加用户的权限,你将可以添加超级用户,这些超级用户将可以修改其他用户。 所以Django同时要求添加权限修改权限作为一种轻量的安全措施。

仔细考虑一下你是如何允许用户管理权限的。 如果你赋予了一个非超级用户编辑用户的能力,这和给他们超级用户的权限在最终效果上是一样的,因为他们将能够提升他们自己下面的用户的权限。

更改密码

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