zoukankan      html  css  js  c++  java
  • DRF认证之源码详解

    一. DRF认证之源码详解

    1. dispatch()源码执行流程详解

      客户端所有的请求到来之后都会执行dispatch()方法,dispatch()方法会根据不同的请求方式,从而触发不同的方法,如GET/POST/PUT/DELETE/UPDATE等方法.

      • 第一步对request进行封装(添加数据)
        request = self.initialize_request(request, *args, **kwargs)

      • 第二步:initial(request, *args, **kwargs):
        #处理版权信息
        #认证
        #权限
        #请求用户进行访问频率的限制

      • 第三步,执行:get/put/post/delete函数

        ​ handler(request, *args, **kwargs)

      • 第四步,对返回结果再次进行加工
        self.response = self.finalize_response(request, response, *args, **kwargs)

      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进行封装(添加数据)
          request = self.initialize_request(request, *args, **kwargs)   
          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
                  
              #第三步,执行:get/put/post/delete函数
              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进行封装(添加数据)

      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(),  # 解析数据,默认有三种方式,可点进去看
              #self.get_authenticators() 先找自己的,没有就找父类的
              authenticators=self.get_authenticators(),#获取认证相关的所有数据并实例化,传入request对象并供request使用
              negotiator=self.get_content_negotiator(),
              parser_context=parser_context
          )
      
    • 获取认证相关的类具体 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]
      
    • 查看认证相关的self.authentication_classes

      authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES 	#默认的
      
    • 接着点击api_settings

      api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)  #接着点击继承的DEFAULTS
      
      #这时候就找到了
      'DEFAULT_AUTHENTICATION_CLASSES': [
          'rest_framework.authentication.SessionAuthentication',
          'rest_framework.authentication.BasicAuthentication'
      
    • 导入SessionAuthentication、BasicAuthentication类:

      from rest_framework.authentication import SessionAuthentication
      from rest_framework.authentication import BasicAuthentication
      
    • 看看authenticate,authenticate_header两个方法

      class BaseAuthentication:
          """
          All authentication classes should extend BaseAuthentication.
          """
      
          def authenticate(self, request):
              """
              Authenticate the request and return a two-tuple of (user, token).
              """
              raise NotImplementedError(".authenticate() must be overridden.")
      
          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.
              """
          	pass
      

    第二步:查看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)
    
    • 点击看一下认证的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,这里的request已经是加工后的request了
    
    • 看一下request.user这个属性
    @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() #用户开始认证了
            return self._user   #返回user
    
    
    • 执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
        def _authenticate(self):
            """
            Attempt to authenticate the request using each authentication instance
            in turn.
            """
            #循环对象列表
            for authenticator in self.authenticators:
                try:
                    #执行每一个对象的authenticate方法
                    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  #返回一个元组,user,和auth,赋给了self,
                    # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
                    return
    
            self._not_authenticated()
    
    • 在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法

      如果用户没有认证成功:self._not_authenticated()

    def _not_authenticated(self):
            """
            Set authenticator, user & authtoken representing an unauthenticated request.
    
            Defaults are None, AnonymousUser & None.
            """
            #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
            self._authenticator = None  #
    
            if api_settings.UNAUTHENTICATED_USER:
                self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
            else:
                self.user = None  # None 表示跳过该认证
    
            if api_settings.UNAUTHENTICATED_TOKEN:
                self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默认值为:None
            else:
                self.auth = None
    
        # (user, token)
        # 表示验证通过并设置用户名和Token;
    

    第三步:执行GET/POST/PUT/DELETE等方法

    第四步:对第三步返回结果进行加工

  • 相关阅读:
    ConCurrent并发包
    volitale最经典理解
    java中关于volatile的理解疑问?
    一直对zookeeper的应用和原理比较迷糊,今天看一篇文章,讲得很通透,分享如下(转)
    架构师成长之路
    rocketmq,zookeeper,redis分别持久化的方式
    rocketmq持久化方式
    源码主干分支开发四大模式
    HDU 4876 ZCC loves cards(暴力剪枝)
    webView用法小结
  • 原文地址:https://www.cnblogs.com/maqian/p/12957090.html
Copyright © 2011-2022 走看看