Django用户认证系统 Web请求中的认证解析


Posted in Python onAugust 02, 2019

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

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

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():

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方法:

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

退出登录logout

logout()

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

from django.contrib.auth import logout
def logout_view(request):
  logout(request)
  # Redirect to a success page.

限制访问

The raw way

使用 request.user.is_authenticated()

再定向:

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]

from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
  ...

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

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

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

from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
  ...

也可以自己定义login_url:

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

urls.py中需定义:

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

测试登录用户

例如,要检测用户的email:

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

可以用装饰器:

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:

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

源码:

def login(request, template_name='registration/login.html',
     redirect_field_name=REDIRECT_FIELD_NAME,
     authentication_form=AuthenticationForm,
     current_app=None, extra_context=None):
  """
  Displays the login form and handles the login action.
  """
  redirect_to = request.POST.get(redirect_field_name,
                  request.GET.get(redirect_field_name, ''))
 
  if request.method == "POST":
    form = authentication_form(request, data=request.POST)
    if form.is_valid():
 
      # Ensure the user-originating redirection url is safe.
      if not is_safe_url(url=redirect_to, host=request.get_host()):
        redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
 
      # Okay, security check complete. Log the user in.
      auth_login(request, form.get_user())
 
      return HttpResponseRedirect(redirect_to)
  else:
    form = authentication_form(request)
 
  current_site = get_current_site(request)
 
  context = {
    'form': form,
    redirect_field_name: redirect_to,
    'site': current_site,
    'site_name': current_site.name,
  }
  if extra_context is not None:
    context.update(extra_context)
  return TemplateResponse(request, template_name, context,
              current_app=current_app)

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参数。

(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 %}

如果自己定制认证系统,可以通过 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内容模板):

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属性:

from django.contrib.auth.forms import AuthenticationForm
 
class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
  def confirm_login_allowed(self, user):
    pass

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

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 }}:

{% 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:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
wxPython窗口中文乱码解决方法
Oct 11 Python
KMP算法精解及其Python版的代码示例
Jun 01 Python
深入浅析python中的多进程、多线程、协程
Jun 22 Python
详解Python读取配置文件模块ConfigParser
May 11 Python
Python-copy()与deepcopy()区别详解
Jul 12 Python
python解析yaml文件过程详解
Aug 30 Python
分享PyCharm的几个使用技巧
Nov 10 Python
浅谈Python类中的self到底是干啥的
Nov 11 Python
Python json转字典字符方法实例解析
Apr 13 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
Jun 03 Python
python 在sql语句中使用%s,%d,%f说明
Jun 06 Python
Python内置方法和属性应用:反射和单例(推荐)
Jun 19 Python
Django用户认证系统 User对象解析
Aug 02 #Python
浅谈python3中input输入的使用
Aug 02 #Python
Pycharm连接远程服务器并实现远程调试的实现
Aug 02 #Python
在PyCharm的 Terminal(终端)切换Python版本的方法
Aug 02 #Python
Django单元测试工具test client使用详解
Aug 02 #Python
Django使用unittest模块进行单元测试过程解析
Aug 02 #Python
pip安装python库的方法总结
Aug 02 #Python
You might like
PHP程序员面试 切忌急功近利(更需要注重以后的发展)
2010/09/01 PHP
php异常处理技术,顶级异常处理器
2012/06/13 PHP
PHP中VC6、VC9、TS、NTS版本的区别与用法详解
2013/10/26 PHP
windows7下安装php的imagick和imagemagick扩展教程
2014/07/04 PHP
CI框架网页缓存简单用法分析
2018/12/26 PHP
Laravel5.4简单实现app接口Api Token认证方法
2019/08/29 PHP
JavaScript中的变量声明早于赋值分析
2012/03/01 Javascript
js replace正则表达式应用案例讲解
2013/01/17 Javascript
浅谈JavaScript 框架分类
2014/11/10 Javascript
JavaScript中的some()方法使用详解
2015/06/09 Javascript
简介可以自动完成UI的AngularJS工具angular-smarty
2015/06/23 Javascript
js实现简单秒表走动的时钟特效
2020/03/25 Javascript
微信小程序-消息提示框实例
2016/11/24 Javascript
微信小程序去哪里找 小程序到底如何使用(附小程序名单)
2017/01/09 Javascript
vue图片加载与显示默认图片实例代码
2017/03/16 Javascript
jQuery实现的简单前端搜索功能示例
2017/10/28 jQuery
Javascript的console['']常用输入方法汇总
2018/04/26 Javascript
Vue中在新窗口打开页面及Vue-router的使用
2018/06/13 Javascript
微信小程序swiper组件实现抖音翻页切换视频功能的实例代码
2020/06/24 Javascript
vue 获取元素额外生成的data-v-xxx操作
2020/09/09 Javascript
[02:19]2018年度DOTA2最佳核心位选手-完美盛典
2018/12/17 DOTA
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
Python机器学习之决策树算法实例详解
2017/12/06 Python
NumPy排序的实现
2020/01/21 Python
英国时尚家具、家居饰品及礼品商店:Graham & Green
2016/09/15 全球购物
工商企业管理应届生求职信
2013/11/03 职场文书
机械设计毕业生自荐信
2014/02/02 职场文书
《桃花心木》教学反思
2014/02/17 职场文书
《童年》教学反思
2014/02/18 职场文书
工作目标责任书
2014/07/23 职场文书
2014最新版群众路线四风整改措施
2014/09/24 职场文书
公司合作协议范文
2014/10/01 职场文书
铁人纪念馆观后感
2015/06/16 职场文书
2016猴年春节问候语
2015/11/11 职场文书
创业计划书之农家乐
2019/10/09 职场文书
SQL Server 中的事务介绍
2022/05/20 SQL Server