Django使用sessions 和 middleware来链接认证系统与请求对象(request objects)。
在每个Web请求中都提供一个 request.user 属性来表示当前用户。如果当前用户未登录,则该属性为AnonymousUser的一个实例,反之,则是一个User实例。
你可以通过is_authenticated()来区分,例如:
if request.user.is_authenticated():
# Do something for authenticated users.
else:
# Do something for anonymous users.
你可以用login()函数来将认证用户加入到当前session中。
login()
在view中使用来登录用户。参数包括一个HttpRequest对象和一个User对象。login() 将用户ID保存到session中(使用Django session framework)。
注意:当用户登陆后对于匿名session的任何数据设置都会保留在session中。
下面的例子来示范如何同时使用 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:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
首先调用authenticate()
如果你自己写代码,一定要确保首先调用authenticate(),然后再调用login()。 authenticate() 会设置User的一个属性来通知认证后台该用户已经成功认证(具体参见: backends documentation),这个属性信息在后续的login处理中需要。因此,如果你直接调用login就会抛出异常。
logout()
通过 django.contrib.auth.login()登录的用户登出时要在view中使用django.contrib.auth.logout() 。使用HttpRequest对象为参数,无返回值。例如:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
注意:logout()不会抛出异常,即使用户并没有登录。
当调用logout()时,当前请求的session数据会彻底清空。如果你需要在用户登出后使用session中的数据,务必在调用django.contrib.auth.logout()后在设置。
最简单直接的方式是:检查request.user.is_authenticated(),如果为False则重定向到登录页面。
from django.shortcuts import redirect
def my_view(request):
if not request.user.is_authenticated():
return redirect('/login/?next=%s' % 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([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])
更简洁的,你可以使用login_required() 修饰符:
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
login_required() 完成以下工作:
一般,用户在成功认证后重定向的链接保存在query string的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,你可能还需要在你的login模板中做相应修改。因为保存重定向路径的模板上下文变量(template context variable)将使用参数 redirect_field_name的值作为key。
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和你的login view 已经正确关联了。例如:在URLconf加入如下缺省内容。
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
Changed in Django 1.5.
settings.LOGIN_URL 也可以接受view函数和named URL patterns。这使得你可以自由定义自己的login view,而不需要去更改你的URLconf设置。
注意:login_required修饰符不会检查user的is_active标志位。
基于特定检查来进行访问控制,基本和之前章节介绍的方式类似。
最简单的方式就是在view中直接使用request.user。例如:下面的view检查用户具有特定domain的email。
def my_view(request):
if not '@example.com' in request.user.email:
return HttpResponse("You can't vote in this poll.")
# ...
user_passes_test(func[, login_url=None])
更简单的的,你可以直接使用 user_passes_test 修饰符:
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
return '@example.com' in user.email
@user_passes_test(email_check)
def my_view(request):
...
user_passes_test() 用“可调用的函数”作为参数,该函数用User作为输入参数,返回布尔值来说明是否通过检查。注意: user_passes_test() 不会自动检查此时用户是否已经登录。
user_passes_test() 还有一个可选的login_url参数,从而可以指定登录页面。(缺省采用settings.LOGIN_URL)
例如:
@user_passes_test(email_check, login_url='/login/')
def my_view(request):
...
permission_required([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.can_vote表示在poll应用中的权限)。
注意: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.
Changed in Django 1.4.
增加了 raise_exception参数,如果给定,修饰符将抛出PermissionDenied,然后提示 the 403 (HTTP Forbidden) view而不是重定向到登录页面。
如果要给class-based generic view应用权限,则需要给类加上View.dispatch的修饰符。详见: Decorating the class.
Django内置提供了几个views可以用来处理登录、登出和密码管理等。这些功能使用了stock auth forms 表单,但也可以自己定义表单。
Django没有为认证views提供缺省模板,但模板上下文可以为view提供 however the template context is documented for each view below.
New in Django 1.4.
所有内置(built-in)views都返回一个TemplateResponse实例,可以让你很方便的定制response数据。具体参见:TemplateResponse documentation.
多数的内置认证views都提供一个URL名称以便使用,具体参见:the URL documentation。
login(request[, template_name, redirect_field_name, authentication_form])
URL name: login
具体参见: the URL documentation.
django.contrib.auth.views.login 工作原理:
需要用户自己来提供login的html模板,缺省是registration/login.html 。这个模板将传递4个模板上下文变量:
如果你不想调用registration/login.html模板,你可以在URLconf中设定特定的view参数来传递template_name参数。例如:下面的URLconf 设置将使用 myapp/login.html 作为模板:
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),
你也可以自己指定登录成功后的重定向链接字段名,通过redirect_field_name 参数。默认的字段名为next.
下面是registration/login.html 模板的原始状态,它假定你有一个base.html模板(其中有content block的定义。
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action="{% url 'django.contrib.auth.views.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>
{% endblock %}
如果你定制实现了认证(具体参见: Customizing Authentication)你可以通过 authentication_form 参数把自定义的认证表单传给login view。该表单的__init__ 方法应该有一个request 的参数,并提供一个 get_user 方法来返回认证后的User对象。
logout(request[, next_page, template_name, redirect_field_name])
登出/注销用户.
URL name: logout
可选参数 Optional arguments:
模板上下文变量 Template context:
logout_then_login(request[, login_url])
注销用户然后重定向到登录链接.
URL name: 为提供缺省链接
可选参数 Optional arguments:
password_change(request[, template_name, post_change_redirect,password_change_form])
允许用户修改密码.
URL name: password_change
可选参数 Optional arguments:
模板上下文变量 Template context:
password_change_done(request[, template_name])
用户修改密码后的页面.
URL name: password_change_done
可选参数 Optional arguments:
password_reset(request[, is_admin_site, template_name, email_template_name,password_reset_form, token_generator, post_reset_redirect, from_email])
通过发送邮件(包含一个只能一次性使用的链接),来让用户重设密码。
Changed in Django 1.4:
标识“未使用密码”(unusable password) (具体参见set_unusable_password() )的用户不能申请重置密码。这样可以防止像LDAP这样的外部认证源的。
URL name: password_reset
可选参数 Optional arguments:
New in Django 1.4.
模板上下文变量 Template context:
Email模板上下文变量 Email template context:
示例: registration/password_reset_email.html (email内容模板):
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %}
相同的模板变量也用在subject template中。邮件主题(Subject)必须是单行文本字符串。
password_reset_done(request[, template_name])
显示用户选择发送密码重置邮件后的页面。如果 password_reset() view中没有显式指定post_reset_redirect链接时,则直接调用本view。
URL name: password_reset_done
Optional arguments:
password_reset_confirm(request[, uidb36, token, template_name, token_generator,set_password_form, post_reset_redirect])
显示输入新密码的表单.
URL name: password_reset_confirm
Optional arguments:
模板上下文变量 Template context:
password_reset_complete(request[, template_name])
view:通知用户已经成功重置了密码
URL name: password_reset_complete
Optional arguments:
redirect_to_login(next[, login_url, redirect_field_name])
重定向到登录页面,登录成功后的在重定向到另一链接。.
Required arguments:
Optional arguments:
如果你不想使用内置的view,也不想重新写相应的表单,仍可以使用django提供相关的表单,在django.contrib.auth.forms中:
注意 Note
内置的认证表单与缺省的User模型对应,如果你使用自定义的用户模型(custom User model),那可能需要自己定义相关的表单。具体的,参见文档using the built-in authentication forms with custom user models.
class AdminPasswordChangeForm
admin后台的用户密码修改表单
class AuthenticationForm
用户登录表单.
class PasswordChangeForm
修改密码表单.
class PasswordResetForm
密码重置表单.
class SetPasswordForm
密码设置表单.
class UserChangeForm
admin后台的用户信息和权限修改表单.
class UserCreationForm
用户创建表单.
当前登录用户及其权限可以在模板变量( template context)中取得,使用RequestContext.
术语 Technicality
下述模板变量仅在使用RequestContext且TEMPLATE_CONTEXT_PROCESSORS 配置包含"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 %}
New in Django 1.5: 用 “if in”.来查询权限
可以直接通过 {% if in %} 语句查询权限,例如:
{% if 'foo' in perms %}
{% if 'foo.can_vote' in perms %}
<p>In lookup works, too.</p>
{% endif %}
{% endif %}