框架之认证接口的源码分析及自定义接口的使用

目录

  • rest_framework框架之认证的使用和源码实现流程

rest_framework框架之认证的使用和源码实现流程

一、认证功能的源码流程

  • (一)、创建视图函数

    Note
    创建视图函数后,前端发起请求,url分配路由,执行视图类,视图类中执行对应方法必须经过dispatch()即调度方法

    from rest_framework.views import APIView
    from django.shortcuts import HttpResponse
    import json

    class DogView(APIView):
    def get(self, request, *args, **kwargs):
    result = {
    ‘code‘: ‘10000‘,
    ‘msg‘: ‘数据创建成功‘
    }
    return HttpResponse(json.dumps(result))

      def post(self, request, *args, **kwargs):
          return HttpResponse('创建一条订单')
    
      def put(self, request, *args, **kwargs):
          return HttpResponse('更新一条订单')
    
      def delete(self, request, *args, **kwargs):
          return HttpResponse('删除一条订单')
  • (二)、运行dispatch方法

    Note
    如果自己定义了dispatch方法,则程序运行自定义方法,如果没有,程序运行源码中的dispatch方法。从dispatch方法中可以找到原生request在作为参数传递后被initialize_request()函数进行了加工,通过加工的request获得的值包括原生的request和BaseAuthentication实例化对象,所以我们需要找到initialize_request()。

    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已经不是原来的request,还包括了其他的参数,
    可以通过新的request获取到内部包含的参数
    加工后的request : Restquest(
    request,
    parsers=self.get_parsers(),
    authenticators=self.get_authenticators(),

          negotiator=self.get_content_negotiator(),
          parser_context=parser_context
      ))
      '''
      self.request = request
      self.headers = self.default_response_headers  # deprecate?
    
      try:
          self.initial(request, *args, **kwargs)
          # 把加工后的request当作参数传递给了initial()函数
          # 需要把在这里查找initial()函数
          # 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
  • 查看initialize_request()函数

    Note
    在initialize_request()函数中返回了authenticators, 通过观察可以看出,authenticators的值来自于另外一个函数get_authenticators()。

    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(),
          # authenticators获取到的是实例化后的类对象列表,即[Foo(), Bar()]
          negotiator=self.get_content_negotiator(),
          parser_context=parser_context
      )
  • 找到函数self.get_authenticators()

    Note
    这个函数中实质上是把一个认证类列表实例化为对象列表进行返回,这里就可以得出在上一个驶入函数中的authenticators是一个实例化对象列表。需要继续往源头找,查找authentication_classes

    def get_authenticators(self):
    """
    Instantiates and returns the list of authenticators that this view can use.
    """
    # 例如self.authentication_classes = [foo, bar]
    return [auth() for auth in self.authentication_classes]
    # 列表生成式,auth获取到的是列表中的类,auth()是把获取到的类对象进行实例化操作

  • 查找authentication_classes类

    Note
    在自己编写的代码中并没有定义authentication_classes类,所以程序会从继承的类中去查找,视图类继承自APIView,所以在APIView中找到类authentication_classes。

    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
      # 继承自APIView中的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

    Summary
    从上述的逻辑可以看出最终要执行的是AUTHENTICATION_CLASSES,所有的程序中都是如果有自定义程序会覆盖掉框架封装好的,没有自定义,程序才会执行封装好的代码。AUTHENTICATION_CLASSES类是这个逻辑中最重要的一环。

  • 上边的逻辑查找到了最基本的Authentication_classes,并且得到加工后的request包含两部分内容:原生的request、Authentication_classes实例化后得到的对象列表,此时需要继续执行dispatch(),执行到try语句时,加工后的request作为参数传递给initial()函数,并执行该函数,此时需要到request.py中查找initial()函数。
      self.request = request
      self.headers = self.default_response_headers  # deprecate?
    
      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
  • 在Request类中查找到request被传递进行,原生的参数在调用的时候格式为:request._request, 加工后的直接是request.属性

    class Request:
    """
    Wrapper allowing to enhance a standard HttpRequest instance.

      Kwargs:
          - request(HttpRequest). The original request instance.
          - parsers_classes(list/tuple). The parsers to use for parsing the
            request content.
          - authentication_classes(list/tuple). The authentications used to try
            authenticating the request's user.
      """
    
      def __init__(self, request, parsers=None, authenticators=None,
                   negotiator=None, parser_context=None):
          assert isinstance(request, HttpRequest), (
              'The `request` argument must be an instance of '
              '`django.http.HttpRequest`, not `{}.{}`.'
              .format(request.__class__.__module__, request.__class__.__name__)
          )
    
          self._request = request
          # 加工后的request被作为参数传递,那么传递后相对于本类即为原生的request。
          self.parsers = parsers or ()
          self.authenticators = authenticators or ()
          self.negotiator = negotiator or self._default_negotiator()
          self.parser_context = parser_context
          self._data = Empty
          self._files = Empty
          self._full_data = Empty
          self._content_type = Empty
          self._stream = Empty
  • 如果进行认证,必须通过user,此时需要查找user程序是否存在,在Request类中找到了user函数,user()方法执行了_authenticate(),查找_authenticate()
      @property
      def user(self):
          """
          Returns the user associated with the current request, as authenticated
          by the authentication classes provided to the request.
          """
          if not hasattr(self, '_user'):
              with wrap_attributeerrors():
                  self._authenticate()
                  # 执行_authenticate()
          return self._user
  • 查找_authenticate(),在_authenticate()方法中查找到Authenticator_classes生成的实例化列表类对象,循环的对象具有authenticate()属性/方法,可以直接调用,并通过条件语句判断,如果登陆返回元组,如果没有登陆返回错误提示。此时基本的逻辑已经梳理完成。
      def _authenticate(self):
          """
          Attempt to authenticate the request using each authentication instance
          in turn.
          """
          for authenticator in self.authenticators:
              try:
                  user_auth_tuple = authenticator.authenticate(self)
              except exceptions.APIException:
                  raise self._not_authenticated()
    
              if user_auth_tuple is not None:
                  self._authenticator = authenticator
                  self.user, self.auth = user_auth_tuple
                  return self._not_authenticated()

二、自定义认证类

通过上述逻辑的整体分析,我们可以编写一个自定义的认证类供视图函数来调用

    from rest_framework import exceptions
    # 创建自定义的认证类
    class MyAuthentication(object):
        def authenticate(self, request):
            token = request._request.GET.get('token')
            # 当前传递的参数request是加工过的,需要通过原生的request(获取方法: _request)获取token信息
            if not token:
            # 如果不存在抛出异常
                raise exceptions.AuthenticationFailed("认证失败")
            # 存在返回元组
            return ('alax', None)

        def authenticate(self, val):
            pass

        class DogView(APIView):
        '''
         需要认证的视图类直接通过authentication_classes=[类名,]的方式来使用
         '''
            authentication_classes = [MyAuthentication]
            def get(self, reqeust, *args, **kwargs):
                result = {
                    'code': '10000',
                    'msg': '获取到所有的数据'
                }
                return HttpResponse(json.dumps(result))

            def post(self, request, *args, **kwargs):
                return HttpResponse("创建Dog")

            def put(self, request, *args, **kwargs):
                return HttpResponse("更新Dog")

            def delete(self, request, *args, **kwargs):
                return HttpResponse("删除Dog")

原文地址:https://www.cnblogs.com/ddzc/p/12121140.html

时间: 2024-11-07 07:40:29

框架之认证接口的源码分析及自定义接口的使用的相关文章

asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetParameterValue方法中有这么一句代码: ModelBindingContext bindingContext = new ModelBindingContext() { FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix

Volley源码分析之自定义MultiPartRequest(文件上传)

本篇内容目录: 使用HttpURLConnection上传文件到服务器案例 自定义支持文件上传的MultiPartRequest Web后台接收文件的部分代码 先来看下HttpURLConnection来文件上传的案例: 1.传送数据到服务器,必定是使用POST请求: //设置请求方式为post httpURLConnection.setDoOutput(true); httpURLConnection.setRequestMethod("POST"); 2.上传文件的HTTP请求中的

MyBatis 源码分析——生成Statement接口实例

JDBC的知识对于JAVA开发人员来讲在简单不过的知识了.PreparedStatement的作用更是胸有成竹.我们最常见用到有俩个方法:executeQuery方法和executeUpdate方法.这俩个方法之外还有一个execute方法.只是这个方法我们很少用.但是mybatis框架就是却用这个方法来实现的.不管mybatis用是哪一个方法来实现.有一点可以肯定--那就是必须得到Statement接口实例.你可以这样子理解mybatis把如何获得Statement接口实例做了一个完美的封装.

插件式换肤框架搭建 - 资源加载源码分析

1. 概述 大部分控件我们都会使用,但是我们未必知道其资源加载的原理,目前换肤的框架比较多我们可以随随便便拿过来用,但早在几年前这些资料是比较少的,如果想做一个换肤的框架那就只能自己一点一点啃源码. 如果说我们现在不去用第三方的开源框架,要做一个换肤的功能,摆在我们面前的其实只有一个问题需要解决,那就是如何读取另外一个皮肤apk中的资源. 所有分享大纲:2017Android进阶之路与你同行 视频讲解地址:http://pan.baidu.com/s/1bC3lAQ 2. 资源加载源码分析 2.

mybatis源码分析之04Mapper接口的动态代理

在工作中,使用mybatis操作数据库,只需要提供一个接口类,定义一些方法,然后调用接口里面的方法就可以CRUD,感觉是牛了一逼! 该篇就是记录一下,mybatis是如何完成这波骚操作的,即分析我们测试代码的第4行. FemaleMapper femaleMapper = sqlSession.getMapper(FemaleMapper.class); 由上篇可知,sqlSession的真实类型是DefaultSqlSession. 所以,我们直接是看DefaultSqlSession#get

Android图片异步加载框架Universal Image Loader的源码分析

项目地址:https://github.com/nostra13/android-universal-image-loader 1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL. 简单的说 UIL 就做了一件事--获取图片并显示在相应的控件上. 1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化I

java集合框架07——Map架构与源码分析

前几节我们对Collection以及Collection中的List部分进行了分析,Collection中还有个Set,由于Set是基于Map实现的,所以这里我们先分析Map,后面章节再继续学习Set.首先我们看下Map架构图: 从图中可以看出: 1. Map是一个接口,Map中存储的内容是键值对(key-value). 2. 为了方便,我们抽象出AbstractMap类来让其他类继承,该类实现了Map中的大部分API,其他Map的具体实现就可以通过直接继承AbatractMap类即可. 3.

java集合框架02——Collection架构与源码分析

Collection是一个接口,它主要的两个分支是List和Set.如下图所示: List和Set都是接口,它们继承与Collection.List是有序的队列,可以用重复的元素:而Set是数学概念中的集合,不能有重复的元素.List和Set都有它们各自的实现类. 为了方便,我们抽象出AbstractCollection类来让其他类继承,该类实现类Collection中的绝大部分方法.AbstractList和AbstractSet都继承与AbstractCollection,具体的List实现

*CI框架装载器Loader.php源码分析

http://www.bitscn.com/pdb/php/201411/404680.html 顾名思义,装载器就是加载元素的,使用CI时,经常加载的有: $this->load->library()$this->load->view()$this->load->model()$this->load->database()$this->load->helper()$this->load->config()$this->load