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
posted @ 2019-11-27 11:46  LBZHK  阅读(98)  评论(0编辑  收藏  举报