二、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 ...
随机推荐
- python json 访问与字符串截取
# req = requests.Request(url=url, headers=headers, data=data) # html = requests.get(req) # print(htm ...
- 在Django中Session的那点事!
1.session是什么 首先引入度娘的解释:Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 We ...
- Linux基础操作-分区概念
开启Linux系统前添加一块大小为20G的SCSI硬盘 开启系统,右击桌面,打开终端 为新加的硬盘分区,一个主分区大小为10G,剩余空间给扩展分区,在扩展分区上划分两个逻辑分区,大小各5G 进入分区工 ...
- 字典树&&01字典树专题&&对字典树的理解
对于字典树和01字典树的一点理解: 首先,字典树建树的过程就是按照每个数的前缀来的,如果你要存储一个全小写字母字符串,那么这个树每一个节点最多26个节点,这样的话,如果要找特定的单词的话,按照建树的方 ...
- Shiro认证的另一种方式
今天在学习shiro的时候使用另一种shiro验证的方式. 总体的思路是: (1)先在自己的方法中进行身份的验证以及给出提示信息.(前提是将自己的验证方法设为匿名可访问) (2)当验证成功之后到Shi ...
- 如何更方便的查看Linux内核代码的更新记录【转】
转自:http://blog.csdn.net/lee244868149/article/details/44302819 Linux内核的更新非常的快,如何快速的了解这些更新呢?最一般的办法就是把新 ...
- 安装mysql5.5的时候出现Error Nr.1045
解决办法: 1.删除注册表几个键值:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL HKEY_L ...
- SDN核心技术剖析和实战指南---读书笔记
第一章 SDN定义如下: SDN是一种新兴的基于软件的网络架构及技术,其最大的特点在于具有松耦合的控制平面与数据平面.支持集中化的网络状态控制.实现底层网络设施对上层应用的透明. SDN和NFV: O ...
- ajax代码示例
function loadXMLDoc(idName,url,sendOut) { var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, ...
- 利用mysql的binlog恢复数据
MySQL Binary Log也就是常说的bin-log, ,是mysql执行改动产生的二进制日志文件,其主要作用有两个: * 数据回复 * 主从数据库.用于slave端执行增删改,保持与maste ...