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实现发送和获取手机短信验证码
Jan 15 Python
使用Python的Twisted框架构建非阻塞下载程序的实例教程
May 25 Python
详解python3中socket套接字的编码问题解决
Jul 01 Python
python使用多进程的实例详解
Sep 19 Python
十分钟搞定pandas(入门教程)
Jun 21 Python
python实现两张图片拼接为一张图片并保存
Jul 16 Python
Python Opencv提取图片中某种颜色组成的图形的方法
Sep 19 Python
python实现输入任意一个大写字母生成金字塔的示例
Oct 27 Python
关于TensorFlow新旧版本函数接口变化详解
Feb 10 Python
python右对齐的实例方法
Jul 05 Python
解决运行出现'dict' object has no attribute 'has_key'问题
Jul 15 Python
Django项目如何正确配置日志(logging)
Apr 29 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查看session内容的函数
2008/08/27 PHP
php str_pad 函数用法简介
2009/07/11 PHP
PHP+shell脚本操作Memcached和Apache Status的实例分享
2016/03/11 PHP
thinkphp分页集成实例
2017/07/24 PHP
JS JavaScript获取Url参数,src属性参数
2021/03/09 Javascript
jquery tools之tabs 选项卡/页签
2009/07/25 Javascript
基于jQuery的图片左右无缝滚动插件
2012/05/23 Javascript
document.execCommand()的用法小结
2014/01/08 Javascript
兼容主流浏览器的JS复制内容到剪贴板
2014/12/12 Javascript
js+html5实现canvas绘制镂空字体文本的方法
2015/06/05 Javascript
下一代Bootstrap的5个特点 超酷炫!
2016/06/17 Javascript
JS基于面向对象实现的多个倒计时器功能示例
2017/02/28 Javascript
js实现自动图片轮播代码
2017/03/22 Javascript
xmlplus组件设计系列之下拉刷新(PullRefresh)(6)
2017/05/03 Javascript
JS实现给json数组动态赋值的方法示例
2020/03/19 Javascript
JS实现数组去重方法总结(六种方法)
2017/07/14 Javascript
微信小程序之发送短信倒计时功能
2017/08/30 Javascript
bootstrap实现嵌套模态框的实例代码
2020/01/10 Javascript
python网络编程之UDP通信实例(含服务器端、客户端、UDP广播例子)
2014/04/25 Python
Python中的字符串操作和编码Unicode详解
2017/01/18 Python
python实现list由于numpy array的转换
2018/04/04 Python
python matplotlib实现双Y轴的实例
2019/02/12 Python
一个可以套路别人的python小程序实例代码
2019/04/09 Python
Django利用cookie保存用户登录信息的简单实现方法
2019/05/27 Python
对DJango视图(views)和模版(templates)的使用详解
2019/07/17 Python
给你一面国旗 教你用python画中国国旗
2019/09/24 Python
python连接mysql有哪些方法
2020/06/24 Python
Selenium及python实现滚动操作多种方法
2020/07/21 Python
Python自动巡检H3C交换机实现过程解析
2020/08/14 Python
大学生个人总结的自我评价
2013/10/05 职场文书
哈理工毕业生的求职信
2013/12/22 职场文书
优秀毕业生自我鉴定
2014/01/19 职场文书
车辆转让协议书
2014/09/24 职场文书
2015年医生个人工作总结
2015/04/25 职场文书
结婚喜宴迎宾词
2015/08/10 职场文书
2016思想纪律作风整顿心得体会
2016/01/23 职场文书