Django contrib auth authenticate函数源码解析

引言

django提供了一个默认的auth系统用于用户的登录和授权,并提供了一定的扩展性,允许开发者自行定义多个验证后台,每个验证后台必须实现authenticate函数,并返回None或者User对象。

默认的后台是django.contrib.auth.backends.ModelBackend,该后台通过用户名和密码进行用户的验证,以settings.AUTH_USER_MODEL作为模型。但是在实际的开发中,相信大家都不会固定的使用用户名以及同一个model进行验证,比如,不同的角色需要不同的model作为验证的数据源,有的角色是使用手机登录,而有的角色使用邮箱登录。

那么,当存在多个验证后台的时候,django是如何制作一个统一的接口进行不同后台的验证呢?

authenticate函数分析

源码:

def authenticate(**credentials):
  """
  If the given credentials are valid, return a User object.
  """
  for backend, backend_path in _get_backends(return_tuples=True):
    try:
      inspect.getcallargs(backend.authenticate, **credentials)
    except TypeError:
      # This backend doesn't accept these credentials as arguments. Try the next one.
      continue

    try:
      user = backend.authenticate(**credentials)
    except PermissionDenied:
      # This backend says to stop in our tracks - this user should not be allowed in at all.
      break
    if user is None:
      continue
    # Annotate the user object with the path of the backend.
    user.backend = backend_path
    return user

  # The credentials supplied are invalid to all backends, fire signal
  user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials))

**credentials

首先可以看到authenticate函数接受的参数,这是指authenticate函数只接受关键字传参,位置传参是不允许的。因此在使用authenticate函数的时候注意不要为了省事而位置传参。

# This will fail
user = authenticate('username', 'password')

# This will success
user = authenticate(username='username', password='password')

inspect.getcallargs(func, *args, **kwargs)
inspect模块是Python官方的标准模块,这个模块对Python的自省功能进行一定的封装。其中inspect.getcallargs检查args和kwargs这些参数是否能被func要求的参数匹配,若匹配成功返回参数字典,如果不能匹配就会raise TypeError。
举个简单的例子。假设在Python中定义这样一个函数:

import inspect
def test_func(arg1, arg2, *args, **kwargs):
  pass
# this will raise TypeError
inspect.getcallargs(test_func, a=1, b=2, c=3)
# TypeError: test_func() missing 2 required positional arguments: 'arg1' and 'arg2'

# this will ok
inspect.getcallargs(test_func, 1, 2, 3, a=1, b=2, c=3)
# {'kwargs': {'b': 2, 'c': 3, 'a': 1}, 'arg2': 2, 'args': (3,), 'arg1': 1}

应用场景

通过inspect.getcallargs的参数过滤功能,只要设置不同后台的authenticate的函数参数,就能在第一步实现不同角色的后台选择。

假设有三种角色,角色1使用用户名登录,角色2使用手机登录,角色3使用手机或者邮箱登录,那么如何通过inspect.getcallargs就选择合适的backend.authenticate呢?

def role3_authenticate(role3_phone=None, role3_email=None, password=None):
  print("role1 authentication.")

def role2_authenticate(role2_phone=None, password=None):
  print("role2 authenticate.")

def role1_authenticate(role1_name=None, password=None):
  print("role2 authenticate.")

methods = [role1_authenticate, role2_authenticate, role3_authenticate]
def authenticate(**credentials):
  for backend in methods:
    try:
      inspect.getcallargs(backend, **credentials)
    except TypeError:
      print("error")
      continue

    backend(**credentials)
    print("end")
    break

如果加入**kwargs则每个authenticate都不会引发TypeError,因为其余参数都设置了默认参数,如果确实需要,则之前的参数使用位置传参。

signal

若用户没有成功登陆,则authenticate发送了一个用户没有成功登陆的信号,开发者可以自行定义接受这个信号的recevier。关于django signal笔者之后还会详细谈及。

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

(0)

相关推荐

  • django框架auth模块用法实例详解

    本文实例讲述了django框架auth模块用法.分享给大家供大家参考,具体如下: auth模块的导入 from django.contrib import auth django中的auth模块有其自己完整的一套方法: 登录验证.注销.用户的创建.比较用户输入的密码是否和数据库的一致.用户信息的修改 1 我们来生成db.sqlite3 (migrations,migrate),打开,从中我们可以找到表 auth_user ,整篇都是围绕这个表进行的 2  这个表里面暂时是空的,我们可以创建 ,例

  • Django实现CAS+OAuth2的方法示例

    CAS Solution 使用CAS作为认证协议. A作为主要的认证提供方(provider). A保留用户系统,其余系统如xxx/www不保留用户系统,即Provider的实现在A. 实现步骤 xxx 选择登录,跳转到LMS的认证界面,CAS读取数据库进行认证,redirect到xxx的界面并且附带ticket在url中,在浏览器中存入Cookie. xxx得到ticket后向CAS发送ticket验证有效性. xxx允许用户访问内部资源. django代码 初始化一个client项目 dja

  • 详解Django-auth-ldap 配置方法

    使用场景 公司内部使用Django作为后端服务框架的Web服务,当需要使用公司内部搭建的Ldap 或者 Windows 的AD服务器作为Web登录认证系统时,就需要这个Django-auth-ldap第三方插件 插件介绍 Django-auth-ldap是一个Django身份验证后端,可以针对LDAP服务进行身份验证.有许多丰富的配置选项可用于处理用户,组和权限,便于对页面和后台的控制 插件介绍地址:Django-auth-ldap 安装方法 注意:需先正确安装python3环境.pip3 和

  • 详解从Django Allauth中进行登录改造小结

    大概来介绍一下 Django Allauth 改造的期间遇到的一些问题和改造方法,在此之前我只想说--Django Allauth 是屑. 为什么我说 Django Allauth 是屑 入职之初我就接到了一些第三方登录的任务,然而 Django Allauth 将内部封装的太好,暴露的 API 不足,更新又慢,issue 和 PR 很少有人处理,当你需要扩展时,很多情况下你只能用一些 hack 的手段去解决问题,非常蛋疼,所以当时就决定慢慢的切到自己的一套 Auth 体系中. 目前已经做的是第

  • django的auth认证,authenticate和装饰器功能详解

    在django中创建表,会自动创建一些django自带的表,先了解用户认证, 认证登录 先要引用 , from django.contrib import auth 有很多方法, 网站先有登录和认证, authenticate(),提供用户认证,验证用户名和密码是否正确,一般需要username ,password两个关键字参数, 认证信息有效,返回有一个User对象.authrenticate()会在User对象上设置一个属性标识,认证了该用户, 创建一个Book表,然后生成数据库 from

  • 详解Django之auth模块(用户认证)

    auth模块简介 auth模块是对登录认证方法的一种封装,之前我们获取用户输入的用户名及密码后需要自己从user表里查询有没有用户名和密码符合的对象, 而有了auth模块之后就可以很轻松的去验证用户的登录信息是否存在于数据库中. 除此之外,auth还对session做了一些封装,方便我们校验用户是否已登录 auth里的方法 如果想使用auth模块的方法,必须要先导入auth模块 from django.contrib import auth django.contrib.auth中提供了许多方法

  • Django实现auth模块下的登录注册与注销功能

    看了好多登录注册和注销的教程,很乱,很迷,然后总结了一下,简单的做了一个登录,注册和注销的页面. 1,首先,使用pycharm创建一个项目 单击File -> 选中Django -> 在右侧Location选中所需的路径,或直接在框里命名 2,现在,你有了一个Django项目 你需要单击左下方的Terminal 创建一个app,命令:python  manage.py startapp Myapp(命名不做要求) 创建一个存放静态文件的文件夹:static(默认为该命名) 项目如下: 3,在W

  • django认证系统 Authentication使用详解

    前言 Django自带一个用户认证系统,用于处理用户账户.群组.许可和基于cookie的用户会话. Django的认证系统包含了身份验证和权限管理两部分.简单地说,身份验证用于核实某个用户是否合法,权限管理则是决定一个合法用户具有哪些权限.往后,'认证'这个词同时代指上面两部分的含义. Django的认证系统主要包括下面几个部分: 用户 许可 组 可配置的密码哈希系统 用于用户登录或者限制访问的表单和视图工具 可插拔的后台系统 类似下面的问题,不是Django认证系统的业务范围,请使用第三方工具

  • Django contrib auth authenticate函数源码解析

    引言 django提供了一个默认的auth系统用于用户的登录和授权,并提供了一定的扩展性,允许开发者自行定义多个验证后台,每个验证后台必须实现authenticate函数,并返回None或者User对象. 默认的后台是django.contrib.auth.backends.ModelBackend,该后台通过用户名和密码进行用户的验证,以settings.AUTH_USER_MODEL作为模型.但是在实际的开发中,相信大家都不会固定的使用用户名以及同一个model进行验证,比如,不同的角色需要

  • vue parseHTML 函数源码解析AST基本形成

    目录 AST(抽象语法树)? 子节点 Vue中是如何把html(template)字符串编译解析成AST 解析html 代码重新改造 接着解析 html (template)字符串 解析div AST(抽象语法树)? 在上篇文章中我们已经把整个词法分析的解析过程分析完毕了. 例如有html(template)字符串: <div id="app"> <p>{{ message }}</p> </div> 产出如下: { attrs: [&q

  • vue parseHTML函数源码解析start钩子函数

    目录 正文 platformGetTagNamespace 源码 isForbiddenTag 函数 addIfCondition是什么 processIfConditions 源码 正文 接上章节:parseHTML 函数源码解析 AST 预备知识 现在我们就可以愉快的进入到Vue start钩子函数源码部分了. start: function start(tag, attrs, unary) { // check namespace. // inherit parent ns if ther

  • vue parseHTML函数源码解析 AST预备知识

    目录 正文 createASTElement函数 解析指令所用正则 parse 函数中的变量 正文 接上章节:parseHTML 函数源码解析AST 基本形成 在正式扎进Vue parse源码之前,我们先了解下他周边的工具函数, 这能帮我们快速的去理解阅读. 还记得我们在上章节讲的element元素节点的描述对象吗? var element = { type: 1, tag: tag, parent: null, attrsList: attrs, children: [] } 在源码中定义了一

  • vue parseHTML 函数源码解析

    目录 正文 函数开头定义的一些常量和变量 while 循环 textEnd ===0 parseStartTag 函数解析开始标签 总结: 正文 接上篇: Vue编译器源码分析AST 抽象语法树 function parseHTML(html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; var canBeLeftOpen

  • jQuery each函数源码分析

    jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 代码 /*! * jQuery源码分析-each函数 * jQuery版本:1.4.2 * * ---------------------------------------------------------- * 函数介绍 * * each函数通过jQuery.extend函数附加到jQuery对象中: * jQuery.extend({ * each:

  • FilenameUtils.getName 函数源码分析

    目录 一.背景 二.源码分析 2.1 问题1:为什么需要 NonNul 检查 ? 2.1.1 怎么检查的? 2.1.2 为什么要做这个检查呢? 2.2 问题2: 为什么不根据当前系统类型来获取分隔符? 三.Zoom Out 3.1 代码健壮性 3.2 代码严谨性 3.3 如何写注释 四.总结 一.背景 最近用到了 org.apache.commons.io.FilenameUtils#getName 这个方法,该方法可以传入文件路径,获取文件名. 简单看了下源码,虽然并不复杂,但和自己设想略有区

  • PHP中array_keys和array_unique函数源码的分析

    性能分析 从运行性能上分析,看看下面的测试代码: $test=array(); for($run=0; $run<10000; $run++) $test[]=rand(0,100); $time=microtime(true); $out = array_unique($test); $time=microtime(true)-$time; echo 'Array Unique: '.$time."\n"; $time=microtime(true); $out=array_k

  • Django应用程序入口WSGIHandler源码解析

    前言 WSGI 有三个部分, 分别为服务器(server), 应用程序(application) 和中间件(middleware). 已经知道, 服务器方面会调用应用程序来处理请求, 在应用程序中有真正的处理逻辑, 在这里面几乎可以做任何事情, 其中的中间件就会在里面展开. Django 中的应用程序 任何的 WSGI 应用程序, 都必须是一个 start_response(status, response_headers, exc_info=None) 形式的函数或者定义了 __call__

  • Django ORM 查询管理器源码解析

    ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从效果上说,它其实是创建了一个可在编程语言里使用的"虚拟对象数据库".ORM 能大大简化并抽象数据库的操作. 假设 django 的一个工程中包含一个名为 Book 的模块(model), 在 views.py 的函数中可能会写出查询语句: # views.py def index(requ

随机推荐