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爬虫
Dec 25 Python
简单介绍Python2.x版本中的cmp()方法的使用
May 20 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
Feb 11 Python
python 对象和json互相转换方法
Mar 22 Python
python实现决策树分类
Aug 30 Python
python中正则表达式 re.findall 用法
Oct 23 Python
Django REST framework 分页的实现代码
Jun 19 Python
Python队列RabbitMQ 使用方法实例记录
Aug 05 Python
python获取引用对象的个数方式
Dec 20 Python
pytorch之Resize()函数具体使用详解
Feb 27 Python
Pytorch中的自动求梯度机制和Variable类实例
Feb 29 Python
python垃圾回收机制原理分析
Apr 13 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与MongoDB简介|安全|M+PHP应用实例详解
2013/06/17 PHP
Yii2基于Ajax自动获取表单数据的方法
2016/08/10 PHP
JavaScript随机排序(随即出牌)
2010/09/17 Javascript
jquery选择器、属性设置用法经验总结
2013/09/08 Javascript
用JQuery实现全选与取消的两种简单方法
2014/02/22 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
javascript实现简单的二级联动
2015/03/19 Javascript
基于JavaScript的操作系统你听说过吗?
2016/01/28 Javascript
JavaScript数组方法大全(推荐)
2016/07/05 Javascript
js无提示关闭浏览器窗口的两种方法分析
2016/11/06 Javascript
jQuery实现CheckBox全选、全不选功能
2017/01/11 Javascript
jQuery手风琴的简单制作
2017/05/12 jQuery
BootStrap导航栏问题记录
2017/07/31 Javascript
jQuery pager.js 插件动态分页功能实例分析
2019/08/02 jQuery
vue-froala-wysiwyg 富文本编辑器功能
2019/09/19 Javascript
VUE 动态组件的应用案例分析
2019/12/02 Javascript
Vue.js获取手机系统型号、版本、浏览器类型的示例代码
2020/05/10 Javascript
linux系统使用python获取cpu信息脚本分享
2014/01/15 Python
python实现将内容分行输出
2015/11/05 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
对DataFrame数据中的重复行,利用groupby累加合并的方法详解
2019/01/30 Python
python argparser的具体使用
2019/11/10 Python
matplotlib bar()实现多组数据并列柱状图通用简便创建方法
2021/02/24 Python
css3中flex布局宽度不生效的解决
2020/12/09 HTML / CSS
HTML5拖放API实现自动生成相框功能
2020/04/07 HTML / CSS
俄罗斯香水在线商店:AromaCode
2019/12/04 全球购物
Eton丹麦官网:精美的男式衬衫
2020/05/27 全球购物
企业管理专业个人求职信范文
2013/09/24 职场文书
两则小学生的自我评价分享
2013/11/14 职场文书
商务助理求职信范文
2014/04/20 职场文书
企业挂职心得体会
2014/09/10 职场文书
2014迎国庆标语大全
2014/09/19 职场文书
2014年销售工作总结与计划
2014/12/01 职场文书
心术观后感
2015/06/11 职场文书
2019最新版火锅店的创业计划书 !
2019/07/12 职场文书
Go语言读取txt文档的操作方法
2022/01/22 Golang