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中尾递归用法实例详解
Apr 28 Python
用Python中的字典来处理索引统计的方法
May 05 Python
Python urllib、urllib2、httplib抓取网页代码实例
May 09 Python
Python解决N阶台阶走法问题的方法分析
Dec 28 Python
Python Xml文件添加字节属性的方法
Mar 31 Python
python清除函数占用的内存方法
Jun 25 Python
Python 最大概率法进行汉语切分的方法
Dec 14 Python
通过实例学习Python Excel操作
Jan 06 Python
基于python 取余问题(%)详解
Jun 03 Python
python利用appium实现手机APP自动化的示例
Jan 26 Python
详解Python生成器和基于生成器的协程
Jun 03 Python
Python  序列化反序列化和异常处理的问题小结
Dec 24 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 事件机制(2)
2011/03/23 PHP
邮箱正则表达式实现代码(针对php)
2013/06/21 PHP
php读取文件内容的几种方法详解
2013/06/26 PHP
php禁止某ip或ip地址段访问的方法
2015/02/25 PHP
php正则修正符用法实例详解
2016/12/29 PHP
php+redis消息队列实现抢购功能
2018/02/08 PHP
jquery 1.4.2发布!主要是性能与API
2010/02/25 Javascript
Jquery 获取checkbox的checked问题
2011/11/16 Javascript
JavaScript 开发工具webstrom使用指南
2014/12/09 Javascript
jquery实现页面百叶窗走马灯式翻滚显示效果的方法
2015/03/12 Javascript
如何用angularjs制作一个完整的表格
2016/01/21 Javascript
Javascript技术栈中的四种依赖注入详解
2016/02/23 Javascript
JavaScript lodash常见用法系列小结
2016/08/24 Javascript
vue.js入门教程之基础语法小结
2016/09/01 Javascript
JavaScript的new date等日期函数在safari中遇到的坑
2016/10/24 Javascript
BootStrap整体框架之基础布局组件
2016/12/15 Javascript
js获取地址栏参数的两种方法
2017/06/27 Javascript
Vue0.1的过滤代码如何添加到Vue2.0直接使用
2017/08/23 Javascript
angular 未登录状态拦截路由跳转的方法
2018/10/09 Javascript
angularjs自定义过滤器demo示例
2019/08/24 Javascript
Element Input输入框的使用方法
2020/07/26 Javascript
Vue组件跨层级获取组件操作
2020/07/27 Javascript
使用Python实现一个简单的项目监控
2015/03/31 Python
简单介绍Python中的JSON模块
2015/04/08 Python
在Python的Django框架中用流响应生成CSV文件的教程
2015/05/02 Python
简介Python的collections模块中defaultdict类型的用法
2016/07/07 Python
Python scikit-learn 做线性回归的示例代码
2017/11/01 Python
python中的闭包函数
2018/02/09 Python
python三引号如何输入
2020/07/06 Python
解决Python 写文件报错TypeError的问题
2020/10/23 Python
平民服装店创业计划书
2014/01/17 职场文书
小学新学期寄语
2014/04/02 职场文书
小学生感恩演讲稿
2014/04/25 职场文书
初中班级口号
2014/06/09 职场文书
司法局2014法制宣传日活动总结
2014/11/01 职场文书
2015年教师国培感言
2015/08/01 职场文书