Django 1.5auth

古畅
2023-12-01


Web请求中的认证 Authentication inWeb requests

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.

如何登录 How to log a user in

你可以用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就会抛出异常。

如何登出How to log a user out

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()后在设置。

限制访问 Limiting access to logged-in users

简易方法 The raw way

最简单直接的方式是:检查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 修饰符

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() 完成以下工作:

  • 如果用户未登录,则重定向到settings.LOGIN_URL,在Query String中传递当前绝对路径。例如: /accounts/login/?next=/polls/3/.
  • 如果用户已登录,则正常执行view。在View的代码可假定用户已经登录。

一般,用户在成功认证后重定向的链接保存在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标志位。

访问限制 Limiting access to logged-in users that pass a test

基于特定检查来进行访问控制,基本和之前章节介绍的方式类似。

最简单的方式就是在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修饰符

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而不是重定向到登录页面。

给泛型views应用权限Applying permissions to generic views

如果要给class-based generic view应用权限,则需要给类加上View.dispatch的修饰符。详见: Decorating the class.

认证Views Authentication Views

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 工作原理:

  • 如果是GET方法, 将显示登录表单,可以将其内容POST到相同的URL上,不再赘述。
  • 如果是POST 方法,用户提交了安全凭证。它首先会尝试登录,如果成功,view就重定向到next指定的的链接。如果next 未设置,则重定向到settings.LOGIN_REDIRECT_URL(一般缺省值为accounts/profile/)。如果登录失败,则再次显示登录表单。

需要用户自己来提供login的html模板,缺省是registration/login.html 。这个模板将传递4个模板上下文变量:

  • form: 一个表单对象,表示AuthenticationForm.
  • next: 登录成功后的重定向链接,可以包含一个query string中。
  • site: 当前网站,根据 SITE_ID 设置。如果你并没有安装site框架,这个变量将设定为一个 RequestSite实例,它从当前 HttpRequest中取得站点名和域名。
  • site_name: 是 site.name的一个别名。如果你没有安装site框架,它将会被设为 request.META['SERVER_NAME']的值。具体参见 The “sites” framework.

如果你不想调用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:

  • next_page: 注销后的重定向链接.
  • template_name: 注销后的模板名称。默认值为registration/logged_out.html 。
  • redirect_field_name: 包含重定向链接的字段名称,缺省值为next_page

模板上下文变量 Template context:

  • title: 本地化的 “Logged out”字串.
  • site: 当前网站,根据 SITE_ID 设置。如果你并没有安装site框架,这个变量将设定为一个 RequestSite实例,它从当前 HttpRequest中取得站点名和域名。
  • site_name: 是 site.name的一个别名。如果你没有安装site框架,它将会被设为 request.META['SERVER_NAME']的值。具体参见 The “sites” framework.

logout_then_login(request[, login_url])

注销用户然后重定向到登录链接.

URL name: 为提供缺省链接

可选参数 Optional arguments:

  • login_url: 登陆页面的重定向链接,缺省值为 settings.LOGIN_URL。

password_change(request[, template_name, post_change_redirect,password_change_form])

允许用户修改密码.

URL name: password_change

可选参数 Optional arguments:

  • template_name: 密码修改表单的模板名,缺省值为registration/password_change_form.html 。
  • post_change_redirect: 密码修改后的重定向链接。
  • password_change_form: 自定义的密码修改表单,包括一个user 参数。缺省值为PasswordChangeForm.

模板上下文变量 Template context:

  • form: 密码修改表单 (参见上面的 password_change_form ).

password_change_done(request[, template_name])

用户修改密码后的页面.

URL name: password_change_done

可选参数 Optional arguments:

  • template_name: 模板名称,缺省为registration/password_change_done.html.

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:

  • template_name: 模板名称,缺省值为registration/password_reset_form.html。
  • email_template_name: 用来生成带充值链接email的模板名称,缺省值为registration/password_reset_email.html。
  • subject_template_name: 用来生成邮件主题的模板名称,缺省值为  registration/password_reset_subject.txt。

New in Django 1.4.

  • password_reset_form: 重设密码的表单,缺省值为 PasswordResetForm.
  • token_generator: 检查一次性链接的类实例,缺省值为default_token_generator, 其类为django.contrib.auth.tokens.PasswordResetTokenGenerator.
  • post_reset_redirect: 密码重置后的重定向链接.
  • from_email: 邮件地址,缺省值为DEFAULT_FROM_EMAIL.

模板上下文变量 Template context:

  • form: 密码重置的表单 (见上: password_reset_form )

Email模板上下文变量 Email template context:

  • email: user.email的别名
  • user: 当前用户,发邮件时将取得其 email 字段。只有激活的用户才能重置密码。 (User.is_active is True).
  • site_name: site.name的别名。如果你未安装site framework,则取request.META['SERVER_NAME']的值. 详细参见:The “sites” framework.
  • domain: site.domain的别名. 如果你未安装site framework,则取request.get_host()的值。
  • protocol: http 或 https
  • uid: 用户ID(base 36编码).
  • token: 用来检查链接是否有效的token(令牌).

示例: 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:

  • template_name:模板名称,缺省值为registration/password_reset_done.html 

password_reset_confirm(request[, uidb36, token, template_name, token_generator,set_password_form, post_reset_redirect])

显示输入新密码的表单.

URL name: password_reset_confirm

Optional arguments:

  • uidb36: 用户ID(base 36编码)。缺省值为None.
  • token:用来检查密码是否有效的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.

模板上下文变量 Template context:

  • form: 密码设置表单 (见上:set_password_form )
  • validlink: Boolean, 重置链接是否有效

password_reset_complete(request[, template_name])

view:通知用户已经成功重置了密码

URL name: password_reset_complete

Optional arguments:

  • template_name: 模板名称,缺省值registration/password_reset_complete.html.

Helper functions

redirect_to_login(next[, login_url, redirect_field_name])

重定向到登录页面,登录成功后的在重定向到另一链接。.

Required arguments:

  • next: 登录成功后的链接.

Optional arguments:

  • login_url: 登陆页面链接,缺省值:settings.LOGIN_URL。
  • redirect_field_name: 重定向字段名称,缺省值为next。

内置表单 Built-in forms

如果你不想使用内置的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

用户创建表单.

模板中的认证信息 Authentication data in templates

当前登录用户及其权限可以在模板变量( template context)中取得,使用RequestContext.

术语 Technicality

下述模板变量仅在使用RequestContext且TEMPLATE_CONTEXT_PROCESSORS 配置包含"django.contrib.auth.context_processors.auth"时有效(即缺省配置)。具体参见RequestContext docs.

Users

在渲染模板 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,则此变量不存在。

权限 Permissions

当前登录用户的权限保存在模板变量 {{ 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 %}
 类似资料:

相关阅读

相关文章

相关问答