您的位置:首页 > 产品设计 > UI/UE

Django1.5内置的用户认证系统介绍(之四)Authentication in Web requests --by hillfree

2013-04-15 19:08 851 查看
说明:网上有关Django用户系统的内容不少,但是好像没有针对Django1.5的。可能是因为Django1.5目前用的人还不多吧。(python3.x貌似也是这种情况)。因为自己要用,所以顺手在学习官方文档的过程中,边看边译。基本忠于原文(>95%),小部分太啰嗦的内容就适当意译、简化了。后续还会加入部分自己的体会(会注出),供参考。如有错讹、不准确之处,还请大家指教。

Source:

https://docs.djangoproject.com/en/1.5/topics/auth/default/#auth-web-requests

Web请求中的认证Authenticationin
Webrequests

Django使用sessions和middleware来链接认证系统与请求对象(requestobjects)。

在每个Web请求中都提供一个request.user属性来表示当前用户。如果当前用户未登录,则该属性为AnonymousUser的一个实例,反之,则是一个User实例。

你可以通过is_authenticated()来区分,例如:

ifrequest.user.is_authenticated():

#Dosomethingforauthenticatedusers.

else:

#Dosomethingforanonymoususers.


如何登录Howtologauserin

你可以用login()函数来将认证用户加入到当前session中。

login()

在view中使用来登录用户。参数包括一个HttpRequest对象和一个User对象。login()将用户ID保存到session中(使用Djangosessionframework)。

注意:当用户登陆后对于匿名session的任何数据设置都会保留在session中。

下面的例子来示范如何同时使用authenticate()和login():

fromdjango.contrib.authimportauthenticate,login


defmy_view(request):

username=request.POST['username']

password=request.POST['password']

user=authenticate(username=username,password=password)

ifuserisnotNone:

ifuser.is_active:

login(request,user)

#Redirecttoasuccesspage.

else:

#Returna'disabledaccount'errormessage

else:

#Returnan'invalidlogin'errormessage.


首先调用authenticate()

如果你自己写代码,一定要确保首先调用authenticate(),然后再调用login()。authenticate()会设置User的一个属性来通知认证后台该用户已经成功认证(具体参见:backendsdocumentation),这个属性信息在后续的login处理中需要。因此,如果你直接调用login就会抛出异常。

如何登出Howtologauserout

logout()

通过django.contrib.auth.login()登录的用户登出时要在view中使用django.contrib.auth.logout()。使用HttpRequest对象为参数,无返回值。例如:

fromdjango.contrib.authimportlogout


deflogout_view(request):

logout(request)

#Redirecttoasuccesspage.


注意:logout()不会抛出异常,即使用户并没有登录。

当调用logout()时,当前请求的session数据会彻底清空。如果你需要在用户登出后使用session中的数据,务必在调用django.contrib.auth.logout()后在设置。

限制访问Limitingaccesstologged-inusers

简易方法Therawway

最简单直接的方式是:检查request.user.is_authenticated(),如果为False则重定向到登录页面。

fromdjango.shortcutsimportredirect


defmy_view(request):

ifnotrequest.user.is_authenticated():

returnredirect('/login/?next=%s'%request.path)

#...


...或显示错误信息:

fromdjango.shortcutsimportrender


defmy_view(request):

ifnotrequest.user.is_authenticated():

returnrender(request,'myapp/login_error.html')

#...


login_required修饰符

login_required([redirect_field_name=REDIRECT_FIELD_NAME,login_url=None])

更简洁的,你可以使用login_required()修饰符:

fromdjango.contrib.auth.decoratorsimportlogin_required


@login_required

defmy_view(request):

...


login_required()完成以下工作:

如果用户未登录,则重定向到settings.LOGIN_URL,在QueryString中传递当前绝对路径。例如:/accounts/login/?next=/polls/3/.

如果用户已登录,则正常执行view。在View的代码可假定用户已经登录。

一般,用户在成功认证后重定向的链接保存在querystring的next参数。如果你想用其他参数名。login_required()中有可选的redirect_field_name参数。

fromdjango.contrib.auth.decoratorsimportlogin_required


@login_required(redirect_field_name='my_redirect_field')

defmy_view(request):

...


注意:如果你设置了redirect_field_name,你可能还需要在你的login模板中做相应修改。因为保存重定向路径的模板上下文变量(templatecontextvariable)将使用参数redirect_field_name的值作为key。

login_required()还提供一个可选的login_url参数,例如:

fromdjango.contrib.auth.decoratorsimportlogin_required


@login_required(login_url='/accounts/login/')

defmy_view(request):

...


注意:如果你不指定login_url参数,你需要确保settings.LOGIN_URL和你的loginview已经正确关联了。例如:在URLconf加入如下缺省内容。

(r'^accounts/login/$','django.contrib.auth.views.login'),


ChangedinDjango1.5.

settings.LOGIN_URL也可以接受view函数和namedURLpatterns。这使得你可以自由定义自己的loginview,而不需要去更改你的URLconf设置。

注意:login_required修饰符不会检查user的is_active标志位。

访问限制Limitingaccesstologged-inusersthatpassatest

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

最简单的方式就是在view中直接使用request.user。例如:下面的view检查用户具有特定domain的email。

defmy_view(request):

ifnot'@example.com'inrequest.user.email:

returnHttpResponse("Youcan'tvoteinthispoll.")

#...


user_passes_test(func[,login_url=None])

更简单的的,你可以直接使用user_passes_test修饰符:

fromdjango.contrib.auth.decoratorsimportuser_passes_test


defemail_check(user):

return'@example.com'inuser.email


@user_passes_test(email_check)

defmy_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/')

defmy_view(request):

...


permission_required修饰符

permission_required([login_url=None,raise_exception=False])

Django提供一种简单的方式来判断用户是否具备某种权限:permission_required()修饰符:

fromdjango.contrib.auth.decoratorsimportpermission_required


@permission_required('polls.can_vote')

defmy_view(request):

...


has_perm()方法中,权限名称采用<applabel>.<permissioncodename>的格式(例如polls.can_vote表示在poll应用中的权限)。

注意:permission_required()也包含一个可选的login_url参数,例如:

fromdjango.contrib.auth.decoratorsimportpermission_required


@permission_required('polls.can_vote',login_url='/loginpage/')

defmy_view(request):

...


login_required()修饰符一样,login_url缺省值为settings.LOGIN_URL.

ChangedinDjango1.4.

增加了raise_exception参数,如果给定,修饰符将抛出PermissionDenied,然后提示the403(HTTPForbidden)view而不是重定向到登录页面。

给泛型views应用权限Applyingpermissionstogenericviews

如果要给class-basedgenericview应用权限,则需要给类加上View.dispatch的修饰符。详见:Decoratingtheclass.

认证ViewsAuthenticationViews

Django内置提供了几个views可以用来处理登录、登出和密码管理等。这些功能使用了stockauthforms表单,但也可以自己定义表单。

Django没有为认证views提供缺省模板,但模板上下文可以为view提供howeverthetemplatecontextisdocumentedforeachviewbelow.

NewinDjango1.4.

所有内置(built-in)views都返回一个TemplateResponse实例,可以让你很方便的定制response数据。具体参见:TemplateResponsedocumentation.

多数的内置认证views都提供一个URL名称以便使用,具体参见:theURLdocumentation。

login(request[,template_name,redirect_field_name,authentication_form])

URLname:login

具体参见:theURLdocumentation.

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:登录成功后的重定向链接,可以包含一个querystring中。

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模板(其中有contentblock的定义。

{%extends"base.html"%}


{%blockcontent%}


{%ifform.errors%}

<p>Yourusernameandpassworddidn'tmatch.Pleasetryagain.</p>

{%endif%}


<formmethod="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>


<inputtype="submit"value="login"/>

<inputtype="hidden"name="next"value="{{next}}"/>

</form>


{%endblock%}


如果你定制实现了认证(具体参见:CustomizingAuthentication)你可以通过authentication_form参数把自定义的认证表单传给loginview。该表单的__init__方法应该有一个request的参数,并提供一个get_user方法来返回认证后的User对象。

logout(request[,next_page,template_name,redirect_field_name])

登出/注销用户.

URLname:logout

可选参数Optionalarguments:

next_page:注销后的重定向链接.

template_name:注销后的模板名称。默认值为registration/logged_out.html。

redirect_field_name:包含重定向链接的字段名称,缺省值为next_page

模板上下文变量Templatecontext:

title:本地化的“Loggedout”字串.

site:当前网站,根据SITE_ID设置。如果你并没有安装site框架,这个变量将设定为一个RequestSite实例,它从当前HttpRequest中取得站点名和域名。

site_name:是site.name的一个别名。如果你没有安装site框架,它将会被设为request.META['SERVER_NAME']的值。具体参见The“sites”framework.

logout_then_login(request[,login_url])

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

URLname:为提供缺省链接

可选参数Optionalarguments:

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

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

允许用户修改密码.

URLname:password_change

可选参数Optionalarguments:

template_name:密码修改表单的模板名,缺省值为registration/password_change_form.html。

post_change_redirect:密码修改后的重定向链接。

password_change_form:自定义的密码修改表单,包括一个user参数。缺省值为PasswordChangeForm.

模板上下文变量Templatecontext:

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

password_change_done(request[,template_name])

用户修改密码后的页面.

URLname:password_change_done

可选参数Optionalarguments:

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])

通过发送邮件(包含一个只能一次性使用的链接),来让用户重设密码。

ChangedinDjango1.4:

标识“未使用密码”(unusablepassword)(具体参见set_unusable_password())的用户不能申请重置密码。这样可以防止像LDAP这样的外部认证源的。

URLname:password_reset

可选参数Optionalarguments:

template_name:模板名称,缺省值为registration/password_reset_form.html。

email_template_name:用来生成带充值链接email的模板名称,缺省值为registration/password_reset_email.html。

subject_template_name:用来生成邮件主题的模板名称,缺省值为registration/password_reset_subject.txt。

NewinDjango1.4.

password_reset_form:重设密码的表单,缺省值为PasswordResetForm.

token_generator:检查一次性链接的类实例,缺省值为default_token_generator,其类为django.contrib.auth.tokens.PasswordResetTokenGenerator.

post_reset_redirect:密码重置后的重定向链接.

from_email:邮件地址,缺省值为DEFAULT_FROM_EMAIL.

模板上下文变量Templatecontext:

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

Email模板上下文变量Emailtemplatecontext:

email:user.email的别名

user:当前用户,发邮件时将取得其email字段。只有激活的用户才能重置密码。(User.is_activeisTrue).

site_name:site.name的别名。如果你未安装siteframework,则取request.META['SERVER_NAME']的值.详细参见:The“sites”framework.

domain:site.domain的别名.如果你未安装siteframework,则取request.get_host()的值。

protocol:http或https

uid:用户ID(base36编码).

token:用来检查链接是否有效的token(令牌).

示例:registration/password_reset_email.html(email内容模板):

Someoneaskedforpasswordresetforemail{{email}}.Followthelinkbelow:

{{protocol}}://{{domain}}{%url'password_reset_confirm'uidb36=uidtoken=token%}


相同的模板变量也用在subjecttemplate中。邮件主题(Subject)必须是单行文本字符串。

password_reset_done(request[,template_name])

显示用户选择发送密码重置邮件后的页面。如果password_reset()view中没有显式指定post_reset_redirect链接时,则直接调用本view。

URLname:password_reset_done

Optionalarguments:

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

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

显示输入新密码的表单.

URLname:password_reset_confirm

Optionalarguments:

uidb36:用户ID(base36编码)。缺省值为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.

模板上下文变量Templatecontext:

form:密码设置表单(见上:set_password_form)

validlink:Boolean,重置链接是否有效

password_reset_complete(request[,template_name])

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

URLname:password_reset_complete

Optionalarguments:

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

Helperfunctions

redirect_to_login(next[,login_url,redirect_field_name])

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

Requiredarguments:

next:登录成功后的链接.

Optionalarguments:

login_url:登陆页面链接,缺省值:settings.LOGIN_URL。

redirect_field_name:重定向字段名称,缺省值为next。

内置表单Built-informs

如果你不想使用内置的view,也不想重新写相应的表单,仍可以使用django提供相关的表单,在django.contrib.auth.forms中:

注意Note

内置的认证表单与缺省的User模型对应,如果你使用自定义的用户模型(customUsermodel),那可能需要自己定义相关的表单。具体的,参见文档usingthebuilt-inauthenticationformswithcustomusermodels.

classAdminPasswordChangeForm

admin后台的用户密码修改表单

classAuthenticationForm

用户登录表单.

classPasswordChangeForm

修改密码表单.

classPasswordResetForm

密码重置表单.

classSetPasswordForm

密码设置表单.

classUserChangeForm

admin后台的用户信息和权限修改表单.

classUserCreationForm

用户创建表单.

模板中的认证信息Authenticationdataintemplates

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

术语Technicality

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

Users

在渲染模板RequestContext时,当前的登录用户(无论是User实例还是AnonymousUser实例)均保存在模板变量{{user}}:

{%ifuser.is_authenticated%}

<p>Welcome,{{user.username}}.Thanksforloggingin.</p>

{%else%}

<p>Welcome,newuser.Pleaselogin.</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%}语句来检查权限了:

{%ifperms.foo%}

<p>Youhavepermissiontodosomethinginthefooapp.</p>

{%ifperms.foo.can_vote%}

<p>Youcanvote!</p>

{%endif%}

{%ifperms.foo.can_drive%}

<p>Youcandrive!</p>

{%endif%}

{%else%}

<p>Youdon'thavepermissiontodoanythinginthefooapp.</p>

{%endif%}


NewinDjango1.5:用“ifin”.来查询权限

可以直接通过{%ifin%}语句查询权限,例如:

{%if'foo'inperms%}

{%if'foo.can_vote'inperms%}

<p>Inlookupworks,too.</p>

{%endif%}

{%endif%}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: