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 ZipFile模块详解
Nov 01 Python
从零学Python之入门(四)运算
May 27 Python
用Python计算三角函数之atan()方法的使用
May 15 Python
30秒轻松实现TensorFlow物体检测
Mar 14 Python
Python使用itertools模块实现排列组合功能示例
Jul 02 Python
Django框架多表查询实例分析
Jul 04 Python
python实现京东秒杀功能
Jul 30 Python
Pandas时间序列:重采样及频率转换方式
Dec 26 Python
keras模型可视化,层可视化及kernel可视化实例
Jan 24 Python
在python下实现word2vec词向量训练与加载实例
Jun 09 Python
Python Opencv实现单目标检测的示例代码
Sep 08 Python
python包的导入方式总结
Mar 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
php注入实例
2006/10/09 PHP
PHP的FTP学习(四)
2006/10/09 PHP
深入PHP autoload机制的详解
2013/06/09 PHP
php中$美元符号与Zen Coding冲突问题解决方法分享
2014/05/28 PHP
PHP判断是手机端还是PC端 PHP判断是否是微信浏览器
2017/03/15 PHP
漂亮的thinkphp 跳转页封装示例
2019/10/16 PHP
Js参数值中含有单引号或双引号问题的解决方法
2013/11/06 Javascript
html5 canvas js(数字时钟)实例代码
2013/12/23 Javascript
jQuery 文本框得失焦点的简单实例
2014/02/19 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
深入理解JavaScript编程中的同步与异步机制
2015/06/24 Javascript
JS实现部分HTML固定页面顶部随屏滚动效果
2015/12/24 Javascript
详解JavaScript中this的指向问题
2017/01/20 Javascript
vue.js的提示组件
2017/03/02 Javascript
详解如何使用vue-cli脚手架搭建Vue.js项目
2017/05/19 Javascript
微信小程序实现流程进度的图样式功能
2018/01/16 Javascript
VUE重点问题总结
2018/03/19 Javascript
基于webpack.config.js 参数详解
2018/03/20 Javascript
使用ECharts实现状态区间图
2018/10/25 Javascript
微信小程序页面滚动到指定位置代码实例
2019/09/07 Javascript
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
pytorch构建网络模型的4种方法
2018/04/13 Python
使用Python进行目录的对比方法
2018/11/01 Python
Python 判断奇数偶数的方法
2018/12/20 Python
在Python中os.fork()产生子进程的例子
2019/08/08 Python
解决python打开https出现certificate verify failed的问题
2020/09/03 Python
Python中的特殊方法以及应用详解
2020/09/20 Python
html5 canvas-1.canvas介绍(hello canvas)
2013/01/07 HTML / CSS
夜大毕业自我鉴定
2013/10/11 职场文书
夜大毕业生自我鉴定
2013/10/31 职场文书
健康状况证明模板
2014/10/23 职场文书
公务员政审材料
2014/12/23 职场文书
公司人事任命通知
2015/04/20 职场文书
关于童年的读书笔记
2015/06/26 职场文书
导游词之平津战役纪念馆
2019/11/04 职场文书
MySQL系列之十二 备份与恢复
2021/07/02 MySQL