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处理图片之PIL模块简单使用方法
May 11 Python
在Python的Django框架中编写编译函数
Jul 20 Python
Python对多属性的重复数据去重实例
Apr 18 Python
Vue的el-scrollbar实现自定义滚动
May 29 Python
python实现kmp算法的实例代码
Apr 03 Python
Django框架中间件(Middleware)用法实例分析
May 24 Python
python的set处理二维数组转一维数组的方法示例
May 31 Python
网易有道2017内推编程题 洗牌(python)
Jun 19 Python
python实现ftp文件传输功能
Mar 20 Python
python批量修改交换机密码的示例
Sep 22 Python
Python 内置函数速查表一览
Jun 02 Python
golang特有程序结构入门教程
Jun 02 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
THINKPHP项目开发中的日志记录实例分析
2014/12/01 PHP
PHP简单实现二维数组赋值与遍历功能示例
2017/10/19 PHP
Laravel中10个有用的用法小结
2019/05/06 PHP
javascript 面向对象 function类
2010/05/13 Javascript
IE6、IE7中setAttribute不支持class/for/rowspan/colspan等属性
2011/08/28 Javascript
JavaScript实现网页对象拖放功能的方法
2015/04/15 Javascript
javascript将DOM节点添加到文档的方法实例分析
2015/08/04 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
JS函数修改html的元素内容,及修改属性内容的方法
2016/10/28 Javascript
jQuery Form表单取值的方法
2017/01/11 Javascript
详谈jQuery Ajax(load,post,get,ajax)的用法
2017/03/02 Javascript
vue-music关于Player播放器组件详解
2017/11/28 Javascript
JavaScript基础心法 深浅拷贝(浅拷贝和深拷贝)
2018/03/05 Javascript
关于vue.js中实现方法内某些代码延时执行
2019/11/14 Javascript
python用字典统计单词或汉字词个数示例
2014/04/22 Python
python中map、any、all函数用法分析
2015/04/21 Python
在ironpython中利用装饰器执行SQL操作的例子
2015/05/02 Python
使用Python下载歌词并嵌入歌曲文件中的实现代码
2015/11/13 Python
python使用mysql数据库示例代码
2017/05/21 Python
Django 导出 Excel 代码的实例详解
2017/08/11 Python
Java及python正则表达式详解
2017/12/27 Python
Tensorflow 查看变量的值方法
2018/06/14 Python
Python中的random.uniform()函数教程与实例解析
2019/03/02 Python
Pyorch之numpy与torch之间相互转换方式
2019/12/31 Python
使用TensorFlow搭建一个全连接神经网络教程
2020/02/06 Python
python程序实现BTC(比特币)挖矿的完整代码
2021/01/20 Python
吉力贝官方网站:Jelly Belly
2019/03/11 全球购物
应届生妇产科护士求职信
2013/10/27 职场文书
采购员岗位职责
2013/11/15 职场文书
市场营销工作计划书
2014/09/15 职场文书
机关干部四风问题自查报告及整改措施
2014/10/26 职场文书
2015年禁毒宣传活动总结
2015/03/25 职场文书
三傻大闹宝莱坞观后感
2015/06/03 职场文书
选调生挂职锻炼工作总结
2015/10/23 职场文书
省级三好学生主要事迹材料
2015/11/03 职场文书
python+opencv实现目标跟踪过程
2022/06/21 Python