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模拟sql语句对员工表格进行增删改查
Jul 05 Python
Python实现输出程序执行进度百分比的方法
Sep 16 Python
如何用python写一个简单的词法分析器
Dec 18 Python
解决webdriver.Chrome()报错:Message:'chromedriver' executable needs to be in Path
Jun 12 Python
在Pytorch中计算卷积方法的区别详解(conv2d的区别)
Jan 03 Python
基于python 取余问题(%)详解
Jun 03 Python
python如何编写win程序
Jun 08 Python
哪些是python中web开发框架
Jun 17 Python
Python scrapy爬取小说代码案例详解
Jul 09 Python
Django nginx配置实现过程详解
Sep 10 Python
基于Python 函数和方法的区别说明
Mar 24 Python
python人工智能human learn绘图可创建机器学习模型
Nov 23 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/03 冲泡冲煮
PHP 中魔术常量的实例详解
2017/10/26 PHP
PHP运用foreach神奇的转换数组(实例讲解)
2018/02/01 PHP
针对thinkPHP5框架存储过程bug重写的存储过程扩展类完整实例
2018/06/16 PHP
jQuery获取当前对象标签名称的方法
2014/02/07 Javascript
js css 实现遮罩层覆盖其他页面元素附图
2014/09/22 Javascript
JavaScript的jQuery库中ready方法的学习教程
2015/08/14 Javascript
AngularJS单选框及多选框实现双向动态绑定
2016/01/13 Javascript
Bootstrap入门书籍之(一)排版
2016/02/17 Javascript
微信小程序 常见问题总结(4058,40013)及解决办法
2017/01/11 Javascript
layui前段框架日期控件使用方法详解
2017/05/19 Javascript
angularjs实现搜索的关键字在正文中高亮出来
2017/06/13 Javascript
微信小程序 密码输入(源码下载)
2017/06/27 Javascript
es7学习教程之Decorators(修饰器)详解
2017/07/21 Javascript
jQuery Datatable 多个查询条件自定义提交事件(推荐)
2017/08/24 jQuery
js实现文件上传功能 后台使用MultipartFile
2018/09/08 Javascript
echarts实现词云自定义形状的示例代码
2019/02/20 Javascript
微信小程序--特定区域滚动到顶部时固定的方法
2019/04/28 Javascript
JavaScript多种滤镜算法实现代码实例
2019/12/10 Javascript
jquery自定义组件实例详解
2020/12/31 jQuery
python文件操作相关知识点总结整理
2016/02/22 Python
matplotlib在python上绘制3D散点图实例详解
2017/12/09 Python
python实现比较文件内容异同
2018/06/22 Python
pyqt5 键盘监听按下enter 就登陆的实例
2019/06/25 Python
详细整理python 字符串(str)与列表(list)以及数组(array)之间的转换方法
2019/08/30 Python
python3 字符串知识点学习笔记
2020/02/08 Python
pytorch 移动端部署之helloworld的使用
2020/10/30 Python
HTML5中判断用户是否正在浏览页面的方法
2014/05/03 HTML / CSS
一套比较完整的软件测试人员面试题
2012/05/13 面试题
中专毕业生自荐信
2013/11/16 职场文书
超市端午节活动方案
2014/01/23 职场文书
中华美德颂演讲稿
2014/05/20 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
工作态度不好检讨书
2015/05/06 职场文书
2015小学五年级班主任工作总结
2015/05/21 职场文书
Prometheus 监控MySQL使用grafana展示
2021/08/30 MySQL