Django用户认证系统(二)Web请求中的认证

原文:https://www.cnblogs.com/linxiyue/p/4060434.html

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

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

1
2
3
4
if  request.user.is_authenticated():
     # Do something for authenticated users.
else :
     # Do something for anonymous users.

登陆login

login()

登陆函数,需要一个HttpRequest对象和一个User对象作参数。login()使用django的session框架,将User的id存储在session中。

同时使用authenticate()和login():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.

如果不知道密码,login方法:

1
2
3
user = MyUser.objects.get(...)
user.backend  =  'django.contrib.auth.backends.ModelBackend'
login(request,user)

退出登录logout

logout()

使用HttpRequest对象为参数,无返回值。例如:

1
2
3
4
5
from  django.contrib.auth  import  logout
 
def  logout_view(request):
     logout(request)
     # Redirect to a success page.

限制访问

The raw way

使用 request.user.is_authenticated() 

再定向:

1
2
3
4
5
6
from  django.shortcuts  import  redirect
 
def  my_view(request):
     if  not  request.user.is_authenticated():
         return  redirect( '/login/?next=%s'  %  request.path)
     # ...

或者:

1
2
3
4
5
6
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]

1
2
3
4
5
from  django.contrib.auth.decorators  import  login_required
 
@login_required
def  my_view(request):
     ...

如果用户未登录,则重定向到 settings.LOGIN_URL,并将现在的url相对路径构成一个next做key的查询字符对附加到 settings.LOGIN_URL后面去:

1
/ accounts / login / ? next = / polls / 3 / .

query字符对的key默认为next,也可以自己命名:

1
2
3
4
5
from  django.contrib.auth.decorators  import  login_required
 
@login_required (redirect_field_name = 'my_redirect_field' )
def  my_view(request):
     ...

也可以自己定义login_url:

1
2
3
4
5
from  django.contrib.auth.decorators  import  login_required
 
@login_required (login_url = '/accounts/login/' )
def  my_view(request):
     ...

urls.py中需定义:

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

测试登录用户

例如,要检测用户的email:

1
2
3
4
def  my_view(request):
     if  not  '@example.com'  in  request.user.email:
         return  HttpResponse( "You can't vote in this poll." )
     # ...

可以用装饰器:

1
2
3
4
5
6
7
8
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):
     ...

也可以改变login_url:

1
2
3
@user_passes_test (email_check, login_url = '/login/' )
def  my_view(request):
     ...

认证Views

当然,我们可以自己定义一些登陆,登出,密码管理的view 函数,而且也更加方便。

不过也可以学习下Django内置的views。

Django没有为认证views提供缺省模板,however the template context is documented for each view below.

所有内置views都返回一个TemplateResponse实例,可以让你很方便的定制response数据。

https://github.com/django/django/blob/master/django/contrib/auth/views.py

多数的内置认证views都提供一个URL名称以便使用。

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

源码:

URL name: login

参数:

template_name: 默认的登陆模板.默认为registration/login.html.
redirect_field_name: 重定向的name,默认为next.
authentication_form: 默认Form. Defaults to AuthenticationForm.
current_app: A hint indicating which application contains the current view. See the namespaced URL resolution strategy for more information.
extra_context: 添加到默认context data中的额外数据,为字典。

django.contrib.auth.views.login does:

如果通过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']的值。

如果你不想调用registration/login.html模板,你可以在URLconf中设定特定的view参数来传递template_name参数。

1
(r '^accounts/login/$' 'django.contrib.auth.views.login' , { 'template_name' 'myapp/login.html' }),

你也可以自己指定重定向链接字段名,通过redirect_field_name 参数。默认的字段名为next.

下面是registration/login.html 模板的原始状态,它假定你有一个base.html模板(其中有content block的定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{ %  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  % }

如果自己定制认证系统,可以通过 authentication_form 参数把自定义的认证表单传给login view。该表单的__init__ 方法应该有一个request 的参数,并提供一个 get_user 方法来返回认证后的User对象。

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

登出用户.

URL name: logout

可选参数:

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

logout_then_login(request[, login_url, current_app, extra_context])

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

可选参数:

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

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

允许用户修改密码.

URL name: password_change

可选参数 Optional arguments:

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

password_change_done(request[, template_name,current_app, extra_context])

用户修改密码后的页面.

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, current_app, extra_context, html_email_template_name])

向用户发送邮件,内含一个一次性链接,来让用户重设密码。

如果提供的邮箱不存在,则不会发送。

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。
password_reset_form: 重设密码的表单,缺省值为 PasswordResetForm.

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

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

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

current_app: A hint indicating which application contains the current view. See the namespaced URL resolution strategy for more information.
extra_context: A dictionary of context data that will be added to the default context data passed to the template.
html_email_template_name: The full name of a template to use for generating a text/html multipart email with the password reset link. By default, HTML email is not sent.

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

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

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

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

显示输入新密码的表单.

password_reset_complete(request[, template_name, current_app, extra_context])

重置密码成功后的表单。

Helper functions

redirect_to_login(next[, login_url, redirect_field_name])

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

参数:

next: 登录成功后的链接.

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

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

内置表单 Built-in forms

class AdminPasswordChangeForm

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

class AuthenticationForm

登录表单。

方法confirm_login_allowed(user)

例如,允许所有的users登陆,不管is_active属性:

1
2
3
4
5
from  django.contrib.auth.forms  import  AuthenticationForm
 
class  AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
     def  confirm_login_allowed( self , user):
         pass

或者只允许活跃用户登陆:

1
2
3
4
5
6
7
8
9
10
11
12
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

密码重置表单.

class SetPasswordForm

密码设置表单.

class UserChangeForm

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

class UserCreationForm

用户创建表单.

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

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

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

1
2
3
4
5
{ %  if  user.is_authenticated  % }
     <p>Welcome, {{ user.username }}. Thanks  for  logging  in .< / p>
{ %  else  % }
     <p>Welcome, new user. Please log  in .< / p>
{ %  endif  % }

如果未使用 RequestContext,则此变量不存在。

使用RequestContext:

1
2
3
4
5
6
7
8
from  django.shortcuts  import  render_to_response
from  django.template  import  RequestContext
 
def  some_view(request):
     # ...
     return  render_to_response( 'my_template.html' ,
                               my_data_dictionary,
                               context_instance = RequestContext(request))

猜你喜欢

转载自www.cnblogs.com/chdltanke/p/10365352.html