我在前面的博客里已经讲过了,我们一般编写API的时候用的方式

class CoursesView(ViewSetMixin,APIView):
pass

这种方式的有点是,灵活性比较大,可以根据自己的业务逻辑来自定义各种组件逻辑。

这边文章,我将带大家对 认证组件做一个源码分析,写这边文章的原因也是因为自己虽然知道怎么写,但是不知道为什么要这么写,今天看了源码,所以想把自己的一些心得写出来和大家分享。

先看代码

 class ShoppingCarView(ViewSetMixin, APIView):
authentication_classes = [LuffyAuthtication,]
def list(self,request, *args, **kwargs):
"""
查看购物车信息
:param args:
:param kwargs:
:return:
"""
try:
ret = BaseResponse()
pay_course_list = []
# key = 'shoppingcar_%s_%s' % (USERID, '*')
key = settings.SHOPCAR_FORMAT.format( request.user.id, "*")
user_key_list = COON.keys(pattern=key) # 取到这个用户对应的所有课程字典 对应的键
for key in user_key_list:
# 对应的每个键值 去取每个课程对应的信息 和价格列表
temp = {
'id': COON.hget(key, 'id').decode('utf8'),
'name': COON.hget(key, 'name').decode('utf8'),
'img': COON.hget(key, 'img').decode('utf8'),
'default': COON.hget(key, 'default').decode('utf8'),
'price_dict': json.loads(COON.hget(key, 'price_dict').decode('utf8')),
}
pay_course_list.append(temp)
ret.data = pay_course_list
except Exception as e:
ret.data = '查看失败'
ret.code = 00000
return Response(ret.dict)

视图类

 1 from app01 import models
2 from rest_framework.authentication import BaseAuthentication
3 from rest_framework.exceptions import AuthenticationFailed
4
5
6 class LuffyAuthtication(BaseAuthentication):
7
8 def authenticate(self, request):
9 """
10 用于做用户认证
11 :param request:
12 :return:
13 """
14 token = request.query_params.get('token')
15 token_obj = models.UserToken.objects.filter(token=token).first()
16 if not token_obj:
17 raise AuthenticationFailed({'code':10000,'error':'认证失败'})
18 return token_obj.user,token_obj

认证类

urlpatterns = [
url(r'^payment/$', payment.PaymentView.as_view({'post': 'create','put': 'update','get':'list'})),
]

url

以上的就是逻辑代码,就是一个必须要验证为注册用户才能查看购物车的内容。

下面来进行源码分析,来看代码是如何走到我自定义的认证类中的。

1.首先从url中分析

  1.先来到视图类中的as.view()方法

  

  而我们的自定义的方法中没有as.view()方法,那就要去父类ViewSetMixin和APIView中去找,好看源码

2.分析源码

  1.先看ViewSetMixin类中

    

    

class ViewSetMixin(object):
"""
This is the magic. Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource. For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions... view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
""" @classonlymethod
def as_view(cls, actions=None, **initkwargs):
"""
Because of the way class based views create a closure around the
instantiated view, we need to totally reimplement `.as_view`,
and slightly modify the view function that is created and returned.
"""
# The suffix initkwarg is reserved for displaying the viewset type.
# eg. 'List' or 'Instance'.
cls.suffix = None # The detail initkwarg is reserved for introspecting the viewset type.
cls.detail = None # Setting a basename allows a view to reverse its action urls. This
# value is provided by the router through the initkwargs.
cls.basename = None # actions must not be empty
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`") # sanitize keyword arguments
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r" % (
cls.__name__, key)) def view(request, *args, **kwargs):
self = cls(**initkwargs)
# We also store the mapping of request methods to actions,
# so that we can later set the action attribute.
# eg. `self.action = 'list'` on an incoming GET request.
self.action_map = actions # Bind methods to actions
# This is the bit that's different to a standard view
for method, action in actions.items():
handler = getattr(self, action)
setattr(self, method, handler) if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get self.request = request
self.args = args
self.kwargs = kwargs # And continue as usual
       # 前面都是在对传参做判断和重新赋值,重要的是下面这一步,最后return 调用了dispatch方法
return self.dispatch(request, *args, **kwargs)

  2.找dispatch方法在哪里,答案肯定是在APIView中

  

 def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
     ## request = Request(.....)
self.request = request
self.headers = self.default_response_headers try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response

    所有的关键点都在dispatch方法里面:

    (1)  request = self.initialize_request(request, *args, **kwargs)

      

def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request) return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), #[BasicAuthentication(),],把对象封装到request里面了
       negotiator=self.get_content_negotiator(), parser_context=parser_context )

    (2)authenticators=self.get_authenticators(),

      通过列表生成式,返回对象的列表  

 def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]

    (3)authentication_classes

    APIView里面有个  authentication_classes   字段  ,这里如果写了静态变量就直接在类的静态变量中找,否则就到全局配置文文件中去找

    可以看到默认是去全局的配置文件找(api_settings)

  

class APIView(View):

    # The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
metadata_class = api_settings.DEFAULT_METADATA_CLASS
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

    (4)开始验证

    (5)self.initial(request,*args,**kwargs)

    def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
self.perform_authentication(request) 认证
self.check_permissions(request)      权限
self.check_throttles(request)        频率

    (6)self.perform_authentication(request)

    

    def perform_authentication(self, request):
"""
Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user   这里没有返回值,直接调用了request.user,那这个user方法是谁的呢????

  

还记得这个Request吧,对没错就是他的,我们点进去看看

    (7)request.user

    

    (8)self._authenticate() 方法

def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
#循环认证类的所有对象
for authenticator in self.authenticators:
try:
#执行认证类的authenticate方法
#这里分三种情况
#1.如果authenticate方法抛出异常,self._not_authenticated()执行
#2.有返回值,必须是元组:(request.user,request.auth)
#3.返回None,表示当前认证不处理,等下一个认证来处理
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple 元祖
return self._not_authenticated()

  返回的元组就是上面自定义认证类代码中的

   token_obj.user,  可以再后续的request.user中取到

token_obj        ,可以再后续的request.auth中取到

 到这里整个认证组件的源码就分析完了

自己写认证类方法梳理

(1)创建认证类

  • 继承BaseAuthentication    --->>1.重写authenticate方法;2.authenticate_header方法直接写pass就可以(这个方法必须写)

(2)authenticate()返回值(三种)

  • None ----->>>当前认证不管,等下一个认证来执行,可用于对请求的过滤上
  • raise exceptions.AuthenticationFailed('用户认证失败')       # from rest_framework import exceptions
  • 有返回值元祖形式:(元素1,元素2)      #元素1复制给request.user;  元素2复制给request.auth

(3)局部使用

  • authentication_classes = [BaseAuthentication,]

(4)全局使用

#设置全局认证
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES":['API.utils.auth.Authentication',]
}

源码流程

--->>dispatch

    --封装request

       ---获取定义的认证类(全局/局部),通过列表生成式创建对象 

     ---initial

       ----peform_authentication

         -----request.user   (每部循环创建的对象)

    

Django REST framework —— 认证组件源码分析的更多相关文章

  1. Django REST framework —— 权限组件源码分析

    在上一篇文章中我们已经分析了认证组件源码,我们再来看看权限组件的源码,权限组件相对容易,因为只需要返回True 和False即可 代码 class ShoppingCarView(ViewSetMix ...

  2. Django-restframework 源码之认证组件源码分析

    Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...

  3. Django rest framework框架——APIview源码分析

    一.什么是rest REST其实是一种组织Web服务的架构,而并不是我们想象的那样是实现Web服务的一种新的技术,更没有要求一定要使用HTTP.其目标是为了创建具有良好扩展性的分布式系统. 可用一句话 ...

  4. Django框架之DRF 认证组件源码分析、权限组件源码分析、频率组件源码分析

    认证组件 权限组件 频率组件

  5. Django rest framework 权限操作(源码分析)

    知识回顾http://www.cnblogs.com/ctztake/p/8419059.html 这一篇是基于上一篇写的,上一篇谢了认证的具体流程,看懂了上一篇这一篇才能看懂, 当用户访问是 首先执 ...

  6. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  7. element-ui 组件源码分析整理笔记目录

    element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...

  8. Django的settings文件部分源码分析

    Django的settings文件部分源码分析 在编写Django项目的过程中, 其中一个非常强大的功能就是我们可以在settings文件配置许多选项来完成我们预期的功能, 并且这些配置还必须大写, ...

  9. ceph-csi组件源码分析(1)-组件介绍与部署yaml分析

    更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi组件源码分析(1)-组件介绍与部署yaml分析 基于tag v3.0.0 ht ...

随机推荐

  1. IBM X3650 M4 安装 Windows Server 2008 R2

    1 准备好  Windows Server 2008 R2 安装用的U盘 2 采用PowerISO制作启动U盘: 或者用Rufus做启动U盘. 3 接上启动U盘 4 设置Bios启动模式为 UEFI ...

  2. STL之iterator源码解析

    摘要 迭代器是一种行为类似指针的对象,本文介绍iterator与traits的关系,以及对traits内容的补充.包含stl_iterator.h的部分内容,并用c++11对其进行略微改写. iter ...

  3. ThinkPHP3开发模式,控制器操作,配置文件,框架语法

    ThinkPHP的开发模式 tp框架有两种使用模式:开发模式(调试模式),一种是生产模式(运行模式) define('APP_DEBUG', true);  //调试模式 define('APP_DE ...

  4. python定时任务APScheduler

    APScheduler定时任务 APScheduler 支持三种调度任务:固定时间间隔,固定时间点(日期),Linux 下的 Crontab 命令.同时,它还支持异步执行.后台执行调度任务. 一.基本 ...

  5. django使用https

    根据以下内容总结了下: http://www.voidcn.com/article/p-xxdfvetx-da.html http://www.voidcn.com/article/p-ezmbnny ...

  6. Locust 性能测试工具安装使用说明

    1. 介绍     它是一个开源性能测试工具.使用 Python 代码来定义用户行为.用它可以模拟百万计的并发用户访问你的系统. 性能工具对比 LoadRunner 是非常有名的商业性能测试工具,功能 ...

  7. 【剑指offer】对称的二叉树

    题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 分析:从上到下直接遍历,利用栈或者队列暂存结点,注意结点的存和取都是成对的 c ...

  8. 004 Thymeleaf学习笔记

    1.Thymeleaf概述 SpringBoot并不推荐使用jsp,但是支持一些模板引擎技术:Freemarker.Thymeleaf.Mustache. 简单说, Thymeleaf 是一个跟 Ve ...

  9. C++ 定义一个指针类型

    #include <iostream>using namespace std; int main(){ int a= 10;  //定义变量a int * p ; //定义个指针P p = ...

  10. swagger list Could not resolve reference because of: Could not resolve point

    swagger list Could not resolve reference because of: Could not resolve point controller的参数要加   @Requ ...