二、django rest_framework源码之认证流程剖析
1 绪言
上一篇中讲了django rest_framework总体流程,整个流程中最关键的一步就是执行dispatch方法。在dispatch方法中,在调用了一个initial方法,所有的认证、权限检查、访问频率控制都是在这个方法中进行的。下面代码为init方法执行这三个操作的源码:
def initial(self, request, *args, **kwargs):
"""
在调用方法处理程序之前运行需要发生的任何事情(例如:认证、权限、访问频率控制)。
"""
……
self.perform_authentication(request)#执行认证
self.check_permissions(request)#检查权限
self.check_throttles(request)#频率控制
这一篇我们来分析一下django rest_framework认证部分的源码。
2 Request对象
这里为什么提到Request对象呢?因为接下来的操作跟它息息相关。我们可以把整个浏览器到服务器的请求过程看作快递运输,Request对象就是我们要运送的包裹,所经历的各个方法就犹如快递中转站或者安检口,会检查Request对象是否符合规定,如果符合规范稍作加工就放行,移送下一个中转站,如果不符合规范,就打回原籍。认证(authentication)显然就是一个安检口,而且还是第一道安检。我们先来看一看这一道安检的入口,即perform_authentication方法的源码:
def perform_authentication(self, request):
request.user
你没有看错,perform_authentication方法在删除注释之后就只有两行代码。代码中的request就是我们要运送的主角(Request对象),是在dispatch方法中第一步操作加工之后获得的,里面封装了原生的request对象(快递包裹中真正要寄送的东西),认证类对象(寄件人身份检查方法),以及其他的一些功能函数。这里的request.user就是封装在Request中的一个方法(可不是属性变量),我们来看看user方法的源码:
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
在user中,如果有“_user”属性,直接返回这个属性,如果没有调用“_authenticate”方法,再来看看“_authenticate”方法:
def _authenticate(self):
# 这里的authenticators就是封装在Request对象中的认证对象(在dispatch第一步操作中封装进去的)
#这个authenticators就犹如快递运送中的寄件人身份核验规范,而且这个规范可能不止一个
for authenticator in self.authenticators:#遍历每一个认证实例
try:
# 执行认证实例中的认证方法(快递开始安检)
user_auth_tuple = authenticator.authenticate(self)#返回一个tuple
except exceptions.APIException:#如果安检没有通过
self._not_authenticated()
raise #抛出异常
if user_auth_tuple is not None:#如果在安检中得到了寄件人的身份信息(也就是那个tuple不为空)
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple#在包裹(Request)中添加寄件人信息和核验信息
return #返回None
self._not_authenticated()#如果认证类设置为空
再来看看认证实例的authenticate方法,我们以TokenAuthentication类为例进行分析,其他的认证类流程大体一致。贴出TokenAuthentication类的authenticate方法源码:
def authenticate(self, request):
#拿到认证信息(token信息)
#形如:Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
auth = get_authorization_header(request).split()#得到['Token', '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b']
#如果认证信息为空,或者第一个元素不是'Token’
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
#如果拿到的认证信息不是两个元素
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = auth[1].decode()#对第二个元素进行解码
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def authenticate_credentials(self, key):
model = self.get_model()#token模型类
try:
# 根据token在数据库中进行核验
#这一步操作就类似于对包裹中的寄件人信息与公安局的身份证号码进行比对
#下面的token是一个token模型类,外键关联user表,可以拿到user信息
token = model.objects.select_related('user').get(key=key)
except model.DoesNotExist:#如果在公安局的数据库中找不到这个寄件人信息
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:#用户未激活
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (token.user, token)#返回一个tuple
至此,认证实例里面的authenticate方法就分析完了。我们在回到_authenticate方法,如果有认证实例列表(self.authenticators)不为空就执行authenticate方法,如果认证实例列表为空或者,或者执行authenticate方法认证失败,就执行_not_authenticated方法,来看看_not_authenticated方法源码:
def _not_authenticated(self):
self._authenticator = None#将认证实例设为空
# 读取配置中的如果没有认证成功生成的用户:默认是匿名用户,可设置为空
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
# 读取配置中的如果没有认证成功生成的用户:默认为空
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
如下是在restframework的settings.py文件中对UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN默认设置:
# Authentication 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', 'UNAUTHENTICATED_TOKEN': None,
这些设置可以在自己项目文件的settings.py文件中进行重新配置。_not_authenticated方法也是直接修改Request对象中的对象和token,然后返回None。_not_authenticated方法执行完之后,一个认证就完成了,如果认证实例列表还有其他元素,就继续下一个认证,认证流程是一样的,如果所有认证实例都遍历完成,那么整个认证流程就跑完了,Request对象中就包含了认证之后的认证信息。
3 自定义认证类
上面分析的是djangorestframework自带的认证类,如果我们要自己创建认证类该怎么做呢?从上面认证类分析中介绍到一个名为authenticate的方法,这个方法在执行认证的时候回被调用,所以自定义认证类的时候,这个方法是必须创建的,另外还有一个名为authenticate_header的方法,也是必须写的。djangorestframework有一个名为BaseAuthentication的类,这是所有认证类的父类,最好继承这个类(也可以不继承,但是那两个方法必须包含)。如下代码是自定义的一个认证类:
class MyTokenAuthentication(BaseAuthentication):
'''自定义的认证类'''
def authenticate(self, request):
token = request.GET.get('token')
success=check_token(token)
if success:
return
else:
raise AuthenticationFailed('认证失败')
def authenticate_header(self, request):
pass
创建好认证类之后如何用上呢,这就涉及到配置认证类了。
4 配置认证类
在视图中,如果某个类需要指定认证类,该如何进行配置呢?有两种方法——局部配置和全局配置。
局部配置是只在配置的当前视图类中生效,配置方法时在试图类中加入下面代码:
authentication_classes = [MyTokenAuthentication , ]
注意:当认证类只有一个时,列表末尾一定要加一个逗号。在局部配置了认证类之后,restframework就只会读取当前配置的认证类,忽略默认设置。
全局配置是在项目的settings.py文件中进行配置,这样的话所有视图都会执行该配置(除非该视图自定义了局部配置)。配制方法是在项目settings.py文件中REST_FRAMEWORK中加入如下代码:
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["myapp.auth. MyTokenAuthentication ",]
}
同样的,当认证类只有一个时,列表末尾一定要加一个逗号,列表中的元素是认证类的路径。
二、django rest_framework源码之认证流程剖析的更多相关文章
- 三、django rest_framework源码之权限流程剖析
1 绪言 上一篇中分析了认证部分的源码,认证后的下一个环节就是权限判定了.事实上,权限判定肯定要与认证联合使用才行,因为认证部分不会对请求进行禁止或者是允许,而只是根据请求中用户信息进行用户身份判断, ...
- 一、django rest_framework源码之总体流程剖析
1 序言 有如下django代码,视图层: from django.http import HttpResponse from rest_framework.views import APIView ...
- 六、django rest_framework源码之解析器剖析
1 绪论 网络传输数据只能传输字符串格式的,如果是列表.字典等数据类型,需要转换之后才能使用但是我们之前的rest_framework例子都没有转换就直接可以使用了,这是因为rest_framewor ...
- 四、django rest_framework源码之频率控制剖析
1 绪言 权限判定之后的下一个环节是访问频率控制,本篇我们分析访问频率控制部分源码. 2 源码分析 访问频率控制在dispatch方法中的initial方法调用check_throttles方法开始. ...
- 七、django rest_framework源码之视图
1 绪言 当大家看大这篇博文的时候,应该对Django rest_framework中的CBV有所了解了,大致来说就是通过定义类来继承APIView类,并在类中定义get.post.put.delet ...
- 五、django rest_framework源码之版本控制剖析
1 绪论 Djangorest_framework的版本控制允许用户更改不同客户端之间的行为,且提供了许多不同的版本控制方案.版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求标头. ...
- Django session 源码流程
流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...
- Django-restframework 源码之认证组件源码分析
Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...
- Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块
目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...
随机推荐
- 在windows的IDEA运行Presto
After building Presto for the first time, you can load the project into your IDE and run the server. ...
- Vue 表格内容根据后台返回状态位填充文字
本文地址:http://www.cnblogs.com/veinyin/p/8534365.html Vue 做表格时我们常用的就是 v-for ,直接把 prop 绑定上去,但是如果表格内容需要我 ...
- hdu 1495 非常可乐 (广搜)
题目链接 Problem Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶 ...
- 解决windows文件夹不能自动刷新的问题
我用的是win7系统,最近忽然发现我的文档文件夹里的文件不能自动刷新了,就是当剪切或删除某个文件后,文件夹里的文件没有变化,看起来文件还在原文件夹中,只有通过手动刷新后才能看到效果,该如何解决? 网上 ...
- Python——杂记
python 最近出错总结: 1.而for..in ..中不要用else if x in y: print else: print2.def fibs(num): ... ...
- 洛谷 P4175: bzoj 1146: [CTSC2008]网络管理
令人抓狂的整体二分题.根本原因还是我太菜了. 在学校写了一个下午写得头晕,回家里重写了一遍,一个小时就写完了--不过还是太慢. 题目传送门:洛谷P4175. 题意简述: 一棵 \(n\) 个结点的树, ...
- Floyd_Warshall算法
Floyd_Warshall算法主要用于求解所有节点对的最短路径,代码如下: #include<iostream> using namespace std; #define Inf 655 ...
- APUE-文件和目录(二)函数access,mask,chmod和粘着位
4.7 函数access和faccessat 当一个进程使用了设置用户ID和设置组ID作为另一个用户(或者组)运行时,这时候有效用户(组)ID和实际用户(组)ID不一样,但进程仍然希望测试实际用户(组 ...
- SSD固态硬盘检测工具AS SSD参数
一. 使用AS SSD Benchmark进行查看 包括了4个方面的测试(顺序读写.4K随机读写.64线程4K读写.寻道时间) AS SSD的主要测试,也是网上最常见得到测试成绩的,是它主界面上持续. ...
- 2->集群架构主机优化流程
集群架构优化流程: 有道笔记分享链接