zoukankan      html  css  js  c++  java
  • 05 drf源码剖析之认证

    05 drf源码剖析之认证

    1. 认证简述

    • 当我们通过Web浏览器与API进行交互时,我们可以登录,然后浏览器会话将为请求提供所需的身份验证。

    • 如果我们以编程方式与API进行交互,则需要在每个请求上显式提供身份验证凭据。

    • 如果我们尝试在不进行身份验证的情况下创建代码段,则会收到错误消息

    2. 认证的使用

    • 创建一个认证类MyAuthentication

      class MyAuthentication(BaseAuthentication):
          def authenticate(self, request):
              """
              Authenticate the request and return a two-tuple of (user, token).
              """
              token = request.query_params.get('token')
              user_object = models.UserInfo.objects.filter(token=token).first()
              if user_object:
                  return (user_object,token)
              return (None,None)
          
      # 最好继承Base类有一个约束
      
    • 在需要认证的类添加authentication_classes

      class OrderView(APIView):
          authentication_classes = [MyAuthentication, ]
          def get(self,request,*args,**kwargs):
              print(request.user)
              print(request.auth)
              return Response('order')
      
      class UserView(APIView):
          authentication_classes = [MyAuthentication,]
          def get(self,request,*args,**kwargs):
              print(request.user)
              print(request.auth)
              return Response('user')
      
    • 全局使用配置,修改匿名用户的名称

      REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":["utils.auth.GeneralAuthentication",],    # 在全局使用认证类,列表里边写认证类的路径,不需要在类内部定义类
        "UNAUTHENTICATED_USER":None,     # 修改匿名用户的昵称
        "UNAUTHENTICATED_TOKEN":None
      }
      

    3. 源码剖析

    • 请求过来先执行dispatch方法

      def dispatch(self, request, *args, **kwargs):
          """
            - 内部封装了 authenticators = [MyAuthentication(), ]
          """
          request = self.initialize_request(request, *args, **kwargs)
      
    • 执行initialize_request方法,将认证对象列表封装到新的request对象中

      def initialize_request(self, request, *args, **kwargs):
          parser_context = self.get_parser_context(request)
      
          return Request(
              request,
              parsers=self.get_parsers(),
              authenticators=self.get_authenticators(), # [MyAuthentication(),]
              negotiator=self.get_content_negotiator(),
              parser_context=parser_context
          )
      
    • 执行get_authenticators方法,将认证类实例化成对象放到认证列表中

      def get_authenticators(self):
          return [ auth() for auth in self.authentication_classes ]
      
    • 认证时会执行Request对象的user方法

      class Request:
      
          def __init__(self, request,authenticators=None):
              self._request = request
              self.authenticators = authenticators or ()
              
      	@property
          def user(self):
              if not hasattr(self, '_user'):
                  with wrap_attributeerrors():
                      self._authenticate()
              return self._user
      
    • _authenticate方法会执行每个认证类的authenticate方法

      def _authenticate(self):
          for authenticator in self.authenticators:
              try:
                  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()
      
    • 认证成功后,将用户对象赋值给request.user

      @user.setter
      def user(self, value):
          self._user = value
          self._request.user = value
      

    4. 总结

    1. 当用户请求过来时,执行dispatch,通过initialize_request方法,
    2. 找到认证的所有类并实例化成对象列表,然后将对象列表封装到新的request对象中。
    3. 执行下面的initial方法,经过认证的request.user方法
    4. 在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,返回值有三种,①抛出异常②返回None③返回一个元组
    5. 返回元组的两个值分别赋值给request.user和request.auth
  • 相关阅读:
    XO Wave-数字音频编纂软件
    LSS:撰写 LaTeX 的扶直对象
    Ubuntu 推出能主动装置编码器、Flash、Java、MS 字体的新包
    目前国内主要有4家“播客”网站
    开始换用 Delphi 2009
    关于 Delphi 中流的使用(10): 压缩与解压缩进度 回复 "ilst" 的问题
    试试带参数的 Exit
    在 Delphi 中调用 JavaScript(2)
    在 Delphi 中调用 JavaScript(1) 回复 "fancy" 的问题
    如何获取重载函数的地址 回复 "flq_00000" 的问题
  • 原文地址:https://www.cnblogs.com/liubing8/p/11941199.html
Copyright © 2011-2022 走看看