zoukankan      html  css  js  c++  java
  • DRF版本和认证源码分析

    request源码封装和版本

    首先举个示例

    #项目urls.py
    urlpatterns = [
         url(r'^api/(?P<version>w+)/', include('api.urls')),
    ]
    
    #app的urls.py
    urlpatterns = [
        url(r'^login/', account.LoginView.as_view()),
        url(r'^article/', article.ArticleView.as_view()),
    ]
    
    #settings.py
    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
        "ALLOWED_VERSIONS":['v1',]
    }
    
    
    #views.py
    import uuid
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import URLPathVersioning
    class LoginView(APIView):
        """
        登录接口
        """
        def post(self,request,*args,**kwargs):
            user_object = models.UserInfo.objects.filter(**request.data).first()
            if not user_object:
                return Response('登录失败')
            random_string = str(uuid.uuid4())
            user_object.token = random_string
            user_object.save()
            # 如果成功给前端返回,随机字符串当token值
            return Response(random_string)
    

    版本源码分析

    # 请求进来之后走APIView的dispatch方法
    def dispatch(self, request, *args, **kwargs):
    	  request = self.initialize_request(request, *args, **kwargs)
         '''
         def initialize_request(self, request, *args, **kwargs):
         		return Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
         
         class Request:
         		self._request = request
         		self.authenticators = authenticators or ()
         
         '''
       
         self.initial(request, *args, **kwargs) 
          '''
           def initial(self, request, *args, **kwargs):
           	 version, scheme = self.determine_version(request, *args, **kwargs)
              request.version, request.versioning_scheme = version, scheme
          
           def determine_version(self, request, *args, **kwargs):
           	 # 先去自定义类中找versioning_class,找不到在去父类找,
           	 # 最后versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
          	 if self.versioning_class is None:
                 return (None, None)
             
              # 实例化版本类对象
              scheme = self.versioning_class()
              
              # 执行版本类中的determine_version方法,并把新request对象传进去
              return (scheme.determine_version方法(request, *args, **kwargs), scheme)
          	
          	# from rest_framework.versioning import URLPathVersioning
          	# URLPathVersioning中的determine_version方法
          	 def determine_version(self, request, *args, **kwargs):
                  version = kwargs.get(self.version_param, self.default_version)
                  if version is None:
                      version = self.default_version
                      
    				# 如果请求中的版本没有在settings定义中,那么报错
                  if not self.is_allowed_version(version):
                      raise exceptions.NotFound(self.invalid_version_message)
                  return version
          
          '''
    

    DRF认证流程

    settings

    REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",]
    }
    

    views

    from rest_framework.views import APIView
    class OrderView(APIView):
       def get(self,request,*args,**kwargs):
          if request.user:
               return Response('order')
          return Response('滚')
    
    

    urls

    urlpatterns = [
        url(r'^login/$', views.LoginView.as_view()),
        url(r'^order/$', views.OrderView.as_view()),
        url(r'^user/$', views.UserView.as_view()),
    ]
    
    

    认证源码分析

    # 请求进来之后走APIView的dispatch方法
    def dispatch(self, request, *args, **kwargs):
         # 执行initialize_request
    	  request = self.initialize_request(request, *args, **kwargs)
         # 此中封装了老的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(),
                authenticators=self.get_authenticators(),###### [MyAuthentication(),]
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
         # 循环authentication_classes,并生成对象列表
         def get_authenticators(self):
            """
            Instantiates and returns the list of authenticators that this view can use.
            """
            return [auth() for auth in self.authentication_classes]
          # 先去自定义类中寻找,如果没有就从settings中寻找
          authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    
    	# 然后执行initial
       self.initial(request, *args, **kwargs)
       # 执行initial中perform_authentication方法
       def initial(self, request, *args, **kwargs):
              self.perform_authentication(request)
       # 执行新request.user类方法
       def perform_authentication(self, 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
       
       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
                    # 账号密码model对象和token分别赋值给user,auth
                    self.user, self.auth = user_auth_tuple
                    return
    
            self._not_authenticated()
          
          
      # 自定义认证类
      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:
             	# 验证账号密码在数据库中是否存在,存在则返回对象和token值
                return (user_object,token)
            return (None,None)
      
    
  • 相关阅读:
    面试题,找出每个产品的最新五个产品,还有其它方法吗 —— 游标加表变量
    SQL排序,重名和调名
    存储过程分页
    Perl/Python 感概
    Perl解析INI文件
    Perl 多进程文件锁
    Windows Sharepoint Services 版本更新
    工作、SOA、MBF...
    Windows Sharepoint Services 版本更新
    被CDOEXM折磨了一把
  • 原文地址:https://www.cnblogs.com/zhuzhizheng/p/12057971.html
Copyright © 2011-2022 走看看