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)
  
posted @ 2019-12-18 08:35  犇羴鱻龘毳  阅读(132)  评论(0编辑  收藏  举报