代码基本结构

  url.py:

from django.conf.urls import url, include
from web.views.s1_api import TestView urlpatterns = [
url(r'^test/', TestView.as_view()),
]

  views.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
'''
认证代码编写区域
'''
return (用户,用户Token) def authenticate_header(self, request):
# 验证失败时,返回的响应头WWW-Authenticate对应的值
pass class TestView(APIView):
authentication_classes = [TestAuthentication, ] def get(self, request, *args, **kwargs):
pass def post(self, request, *args, **kwargs):
pass '''
等等一系列的视图功能方法
'''

  说明:

    1)在authenticate方法的返回值是一个元组,元组中第一个元素是用户名,第二个元素是认证数据token。这个返回值会在我们的视图类中通过request.user 和 request.auth获取到。具体为什么是这两个值,会在后面的源码分析中说明。

    2)认证的返回值有三种情况:

      返回元组(如(1)中所述):认证成功

      返回None:处理下一个认证类

      抛出异常:认证失败

    3)上面的基本结构是做局部的类的认证方式,如果相对绝大多数的类做认证,那么可以通过全局认证的方式实现。该方法在下文中介绍。

    4)authentication_classes 属性变量是一个列表,列表元素是类,一般情况只使用一个认证类。     

源码分析

  1) 为什么要使用authentication_classes 属性变量?

  

  python 的面向对象编程中,我们首先要执行的方法肯定是dispatch方法,所以我们的分析入口就是dispatch方法,在dispatch方法中,可以看到,通过initialize_request方法将django原生的request进行了一次封装。由initialize_request方法的实现过程可以看出,将其封装实例化成了一个Request对象。而authenticators属性就是认证属性。

 

  通过查看get_authenticators方法,可以知道,它的返回值是一个列表生成式,而这个列表生成式中所用的就是我们在认证类中赋值authenticatin_classes属性变量。在查找该变量的定义位置,就看到了它是通过settings配置文件来实现赋值的,除非,在子类中将其赋值。我们的代码就是这样做的。同时,也可以看出,我们可以修改settings配置文件来为全局定义认证规则。

2)为什么要认证类中要使用authenticate方法?

  回到前面说是的dispatch方法来,在做完了对django原生的request的封装和实例化后,紧接着就会开始认证(try...中,捕获异常,如果没有捕获到异常,说明认证成功,就会继续执行下面的反射过程)。认证的过程就包含在上图中的inital方法中,有图可知,是通过perform_authentication方法实现的认证。

  在perform_authentication方法中可以看到,只调用了一个request.user,而这个user一定是方法,不会是属性变量,因为如果是属性变量,那么就一定有语法错误,变量一定是要赋值的,不可能孤零零的写到那里。我们在源码中找到它,就明白了,之所以它能这么写,就是因为有了property装饰器。在user方法中找到_authenticate方法,这就是认证的方法。

 

   在这个方法中,一切答案都就找到了。首先看authenticators,是不是很眼熟,没错它就是前面说的,封装和实例化原生request的Request类中所定义的属性变量。在实例化时,我们就将authentication_classes列表的值通过get_authenticators方法中的列表生成式赋值给了authenticators。再往下看,authenticator.autheneicate(self)中的authenticator是不是就是我们自己定义的认证类,而它在源码中要做“.authenticate(self)”的操作,那自然而然,我们定义的认证类中要实现这个方法了。

  3)为什么认证成功后的返回值在request.user和request.auth中?

  由 2)中最后一个图可知,当我们认证成功后会执行“self.user, self.auth = user_auth_tuple”代码,我们在认证类定义的方法authenticate的返回值就保存在 user_auth_tuple中,所以我们通过request.user 和 request.auth 就可以获取到了。

实例

from django.conf.urls import url, include
from web.viewsimport TestView urlpatterns = [
url(r'^test/', TestView.as_view()),
]

urls.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions token_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
] class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
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
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
val = request.query_params.get('token')
if val not in token_list:
raise exceptions.AuthenticationFailed("用户认证失败") return ('登录用户', '用户token') def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
# 验证失败时,返回的响应头WWW-Authenticate对应的值
pass class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = [] def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response('GET请求,响应内容') def post(self, request, *args, **kwargs):
return Response('POST请求,响应内容') def put(self, request, *args, **kwargs):
return Response('PUT请求,响应内容')

Views.py

扩展:全局认证

  如果要进行全局配置,由上面的源码分析可知,我们只需要在配置文件中配置我们存储到authentication_classes的值即可。但还要注意的是,在写配置文件时,要使用的是路径,所以最好在和views.py同级目录下新建一个文件夹(我习惯叫utils),再在该文件夹下新建一个认证文件(auth.py),将我们的认证类都写到这里。

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES" :['api.utils.auth.MyAuthentication]
}

   MyAuthentication类就是我们写在utils文件夹下auth.py文件中的认证类。

  注意:如果有部分类不需要认证的话,可以在这里类中添加“authentication_classes = []”,即可。

Django Rest Framework之认证的更多相关文章

  1. Django Rest framework 之 认证

    django rest framework 官网 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest fra ...

  2. django rest framework用户认证

    django rest framework用户认证 进入rest framework的Apiview @classmethod def as_view(cls, **initkwargs): &quo ...

  3. Django rest framework 的认证流程(源码分析)

    一.基本流程举例: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/', views.HostView.as_view() ...

  4. Django REST Framework之认证组件

    什么是认证 认证即需要知道是谁在访问服务器,需要有一个合法身份.认证的方式可以有很多种,例如session+cookie.token等,这里以token为例.如果请求中没有token,我们认为这是未登 ...

  5. DRF Django REST framework 之 认证组件(五)

    引言 很久很久以前,Web站点只是作为浏览服务器资源(数据)和其他资源的工具,甚少有什么用户交互之类的烦人的事情需要处理,所以,Web站点的开发这根本不关心什么人在什么时候访问了什么资源,不需要记录任 ...

  6. Django REST framework 之 认证 权限 限制

    认证是确定你是谁 权限是指你有没有访问这个接口的权限 限制主要是指限制你的访问频率 认证 REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案. 接下类我们就自己 ...

  7. 基于django rest framework做认证组件

    先导入要用到的类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions ...

  8. 【django后端分离】Django Rest Framework之认证系统之redis数据库的token认证(token过期时间)

    1:登录视图 redis_cli.py文件: import redis Pool= redis.ConnectionPool(host='localhost',port=6379,decode_res ...

  9. 源码剖析Django REST framework的认证方式及自定义认证

    源码剖析Django REST framework的认证方式 在前面说过,请求到达REST framework的时候,会对request进行二次封装,在封装的过程中会对客户端发送过来的request封 ...

随机推荐

  1. Xutils简

    //解析 private void myinitData() { RequestParams parms=new RequestParams("http://huixinguiyu.cn/A ...

  2. 瞎搞poj1008

    http://poj.org/problem?id=1008 题意: 两种历法: 1.Haab,一年365天,共19个月,前18月有20天(编号为0-19),最后一个月有5天(编号为0-4)pop(1 ...

  3. hive 命令行传入参数

    azkban实现任务重跑 我们执行sql的方式是将hql文件上传到服务器本地.然后执行shell命令 hive " -f ./test_scheduler.hql 注:hive -e 是执行 ...

  4. 我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比(转载)

    转载自:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...

  5. [算法专题] Binary Tree

    1 Same Tree https://leetcode.com/problems/same-tree/ Given two binary trees, write a function to che ...

  6. 定时任务 Wpf.Quartz.Demo.5 (升级版)

    老规矩:先把全部源码上传,见本文底部. 相对于Demo3的区别,就是能自动加载继承了IJob的任务,任务主体程序分离. 在exe执行文件的同级下建一个MyJobs的文件夹,每次会自动扫描该文件夹下的J ...

  7. go语言异常处理

    go语言异常处理 error接口 go语言引入了一个关于错误错里的标准模式,即error接口,该接口的定义如下: type error interface{ Error() string } 对于要返 ...

  8. 浅谈css3长度单位rem,以及移动端布局技巧

    rem是什么? rem是css3中新增加的一个单位属性(font size of the root element),根据页面的根节点的字体大小进行转变的单位.root!!!!!!!!!根节点,也就是 ...

  9. Testing - 软件测试的思维和技巧

    01 - 测试员不仅仅是执行测试用例,对实际结果和预期结果进行比较 测试员其实是参与了设计和执行测试的各个环节:测试架构,环境搭建,测试用例等等,并确定预期输出. 大多数设计测试都是基于业务流程和原理 ...

  10. 关于c++11中的thread库

    c++11中新支持了thread这个库,常见的创建线程.join.detach都能支持. join是在main函数中等待线程执行完才继续执行main函数,detach则是把该线程分离出来,不管这个线程 ...