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 相关文章推荐
优化Python代码使其加快作用域内的查找
Mar 30 Python
浅谈Python中函数的参数传递
Jun 21 Python
Python正则表达式常用函数总结
Jun 24 Python
django允许外部访问的实例讲解
May 14 Python
Python自定义装饰器原理与用法实例分析
Jul 16 Python
在Python dataframe中出生日期转化为年龄的实现方法
Oct 20 Python
Python一个简单的通信程序(客户端 服务器)
Mar 06 Python
Python叠加两幅栅格图像的实现方法
Jul 05 Python
简单了解django orm中介模型
Jul 30 Python
python numpy 反转 reverse示例
Dec 04 Python
pycharm的python_stubs问题
Apr 08 Python
python操作微信自动发消息的实现(微信聊天机器人)
Jul 14 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 中英文混合排版中处理字符串常用的函数
2007/04/12 PHP
php获取当月最后一天函数分享
2015/02/02 PHP
PHP支付系统设计与典型案例分享
2016/08/02 PHP
JS面向对象、prototype、call()、apply()
2009/05/14 Javascript
js验证是否为数字的总结
2013/04/14 Javascript
js中的caller和callee属性介绍和例子
2014/06/07 Javascript
Express.JS使用详解
2014/07/17 Javascript
由ReactJS的Hello world说开来
2015/07/02 Javascript
jQuery事件绑定方法学习总结(推荐)
2016/11/21 Javascript
Vue.js第一天学习笔记(数据的双向绑定、常用指令)
2016/12/01 Javascript
Bootstarp 基础教程之表单部分实例代码
2017/02/03 Javascript
全面解析vue中的数据双向绑定
2017/05/10 Javascript
node.js 中间件express-session使用详解
2017/05/20 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
nodejs中安装ghost出错的原因及解决方法
2017/10/23 NodeJs
详解Angular6 热加载配置方案
2018/08/18 Javascript
ES6的异步终极解决方案分享
2019/07/11 Javascript
[02:53]2018年度DOTA2最佳战队-完美盛典
2018/12/17 DOTA
基于Django框架利用Ajax实现点赞功能实例代码
2018/08/19 Python
python3使用matplotlib绘制散点图
2019/03/19 Python
Python实现的ftp服务器功能详解【附源码下载】
2019/06/26 Python
树莓派4B+opencv4+python 打开摄像头的实现方法
2019/10/18 Python
Python代码块及缓存机制原理详解
2019/12/13 Python
Python API len函数操作过程解析
2020/03/05 Python
CSS+jQuery实现的在线答题功能
2015/04/25 HTML / CSS
英国最大的老式糖果店:A Quarter Of
2017/04/08 全球购物
大学班级干部的自我评价分享
2014/02/10 职场文书
实训报告范文大全
2014/11/04 职场文书
2015年民主生活会发言材料
2014/12/15 职场文书
新教师个人工作总结
2015/02/06 职场文书
2015年清明节扫墓演讲稿
2015/03/18 职场文书
2015年国庆节演讲稿范文
2015/07/30 职场文书
2015年小学语文教师工作总结
2015/10/23 职场文书
创业计划书之酒店
2019/08/30 职场文书
为什么不建议在go项目中使用init()
2021/04/12 Golang
使用CSS定位HTML元素的实现方法
2022/07/07 HTML / CSS