Django contrib auth authenticate函数源码解析


Posted in Python onNovember 12, 2020

引言

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笔者之后还会详细谈及。

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

Python 相关文章推荐
Python中处理字符串之islower()方法的使用简介
May 19 Python
Python编程中的文件读写及相关的文件对象方法讲解
Jan 19 Python
教你用Type Hint提高Python程序开发效率
Aug 08 Python
Python 迭代器与生成器实例详解
May 18 Python
python使用turtle库与random库绘制雪花
Jun 22 Python
使用Python的Dataframe取两列时间值相差一年的所有行方法
Jul 10 Python
Python实现针对json中某个关键字段进行排序操作示例
Dec 25 Python
详解重置Django migration的常见方式
Feb 15 Python
Python爬虫实现使用beautifulSoup4爬取名言网功能案例
Sep 15 Python
python创建ArcGIS shape文件的实现
Dec 06 Python
Python读取文件内容为字符串的方法(多种方法详解)
Mar 04 Python
如何清空python的变量
Jul 05 Python
python 获取字典键值对的实现
Nov 12 #Python
Sentry错误日志监控使用方法解析
Nov 12 #Python
python 利用opencv实现图像网络传输
Nov 12 #Python
Anaconda详细安装步骤图文教程
Nov 12 #Python
Jupyter Notebook安装及使用方法解析
Nov 12 #Python
利用Python发送邮件或发带附件的邮件
Nov 12 #Python
Python如何使用ConfigParser读取配置文件
Nov 12 #Python
You might like
中国第一家无线电行
2021/03/01 无线电
php基础知识:控制结构
2006/12/13 PHP
PHP页面间传递参数实例代码
2008/06/05 PHP
PHP中几种常见的超时处理全面总结
2012/09/11 PHP
Zend Framework教程之视图组件Zend_View用法详解
2016/03/05 PHP
Thinkphp 框架扩展之应用模式实现方法分析
2020/04/27 PHP
JavaScript设置FieldSet展开与收缩
2009/05/15 Javascript
jquery.artwl.thickbox.js  一个非常简单好用的jQuery弹出层插件
2012/03/01 Javascript
Jquery Mobile 自定义按钮图标
2015/11/18 Javascript
js Canvas绘制圆形时钟教程
2017/02/06 Javascript
基于JavaScript定位当前的地理位置
2017/04/11 Javascript
ES6新特性二:Iterator(遍历器)和for-of循环详解
2017/04/20 Javascript
Vue项目中设置背景图片方法
2018/02/21 Javascript
React从react-router路由上做登陆验证控制的方法
2018/05/10 Javascript
Nodejs中的require函数的具体使用方法
2019/04/02 NodeJs
Mpvue中使用Vant Weapp组件库的方法步骤
2019/05/16 Javascript
Vuex,iView UI面包屑导航使用扩展详解
2019/11/04 Javascript
vue.js自定义组件实现v-model双向数据绑定的示例代码
2020/01/08 Javascript
js+canvas实现纸牌游戏
2020/03/16 Javascript
编写Python脚本来获取Google搜索结果的示例
2015/05/04 Python
尝试用最短的Python代码来实现服务器和代理服务器
2016/06/23 Python
Windows下Python2与Python3两个版本共存的方法详解
2017/02/12 Python
python使用Pycharm创建一个Django项目
2018/03/05 Python
如何在VSCode上轻松舒适的配置Python的方法步骤
2019/10/28 Python
线程安全及Python中的GIL原理分析
2019/10/29 Python
python剪切视频与合并视频的实现
2020/03/03 Python
Numpy中的数组搜索中np.where方法详细介绍
2021/01/08 Python
高级方案规划工程师岗位职责
2013/11/29 职场文书
《宋庆龄故居的樟树》教学反思
2014/04/07 职场文书
小学校长汇报材料
2014/08/20 职场文书
校园运动会广播稿
2014/10/06 职场文书
喋血孤城观后感
2015/06/08 职场文书
运动会通讯稿200字
2015/07/20 职场文书
低端且暴利的线上线下创业项目分享
2019/09/03 职场文书
祝福语集锦:给百岁老人祝寿贺词
2019/11/19 职场文书
python利用pandas分析学生期末成绩实例代码
2021/07/09 Python