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正则表达式匹配HTML页面编码
Apr 08 Python
python创建临时文件夹的方法
Jul 06 Python
python3.5仿微软计算器程序
Mar 30 Python
举例讲解Python编程中对线程锁的使用
Jul 12 Python
python的Tqdm模块的使用
Jan 10 Python
使用Python开发SQLite代理服务器的方法
Dec 07 Python
Python数据报表之Excel操作模块用法分析
Mar 11 Python
jupyter notebook oepncv 显示一张图像的实现
Apr 24 Python
利用Vscode进行Python开发环境配置的步骤
Jun 22 Python
Python获取字典中某个key的value
Apr 13 Python
python神经网络Xception模型
May 06 Python
Python实战实现爬取天气数据并完成可视化分析详解
Jun 16 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
PHP+Apache环境中如何隐藏Apache版本
2017/11/24 PHP
PHP连续签到功能实现方法详解
2019/12/04 PHP
TNC vs IO BO3 第二场2.13
2021/03/10 DOTA
禁止F5等快捷键的JS代码
2007/03/06 Javascript
js身份证验证超强脚本
2008/10/26 Javascript
比较搞笑的js陷阱题
2010/02/07 Javascript
ExtJS4 Grid改变单元格背景颜色及Column render学习
2013/02/06 Javascript
验证手机号码的JS方法分享
2013/09/10 Javascript
jQuery ajax dataType值为text json探索分享
2013/09/23 Javascript
js实现checkbox全选和反选示例
2014/05/01 Javascript
AngularJS教程 ng-style 指令简单示例
2016/08/03 Javascript
Vue2.0基于vue-cli+webpack Vuex的用法(实例讲解)
2017/09/15 Javascript
Vue组件和Route的生命周期实例详解
2018/02/10 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
Vue 框架之动态绑定 css 样式实例分析
2018/11/14 Javascript
Vue从TodoList中学父子组件通信
2019/02/05 Javascript
浅谈对于react-thunk中间件的简单理解
2019/05/01 Javascript
NodeJs 模仿SIP话机注册的方法
2019/06/21 NodeJs
Layui 动态禁止select下拉的例子
2019/09/03 Javascript
JS如何生成动态列表
2020/09/22 Javascript
[01:09]DOTAPLUS——DOTA2的新时代
2018/04/04 DOTA
[01:05:41]EG vs Optic Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
Python利用Beautiful Soup模块创建对象详解
2017/03/27 Python
Python生成任意范围任意精度的随机数方法
2018/04/09 Python
python matlibplot绘制多条曲线图
2021/02/19 Python
python变量赋值方法(可变与不可变)
2019/01/12 Python
Python with语句和过程抽取思想
2019/12/23 Python
python通过移动端访问查看电脑界面
2020/01/06 Python
基于python实现破解滑动验证码过程解析
2020/05/28 Python
python定义具名元组实例操作
2021/02/28 Python
django使用多个数据库的方法实例
2021/03/04 Python
挪威户外活动服装和装备购物网站:Bergfreunde挪威
2016/10/20 全球购物
LightInTheBox法国站:中国跨境电商
2020/03/05 全球购物
信息管理专业推荐信
2013/10/29 职场文书
党员学习中共十八大思想报告
2014/09/12 职场文书
收费员岗位职责
2015/02/14 职场文书