Django Rest Framework(二 认证源码流程)

一、CBV回顾

 

class TestView(APIView):
    def dispatch(self, request, *args, **kwargs):
        """
        请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法

        注意:APIView中的dispatch方法有好多好多的功能
        """
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        return Response('GET请求,响应内容')

    def post(self, request, *args, **kwargs):
        return Response('POST请求,响应内容')

    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')

二、使用restful时流程

整体:自建类继承APIView ,APIView又继承View类

入口:CBV/FBV入口都是urls,由此出发

分发:urls 里边使用as_view方法,经过处理到达dispatch方法,在这做分发

终点:执行自定义的认证类

三、图示

 

四、执行详细流程

  • url(r'^test/', TestView.as_view())

进入as_view方法 位置···\site-packages\rest_framework\views.py
  super(APIView, cls).as_view(**initkwargs) 
  调用父类View的as_view() 位置 \site-packages\django\views\generic\base.py
    最终返回 return self.dispatch(request, *args, **kwargs)

  • self.dispatch

self是TestView ,没有dispatch方法,继续向APIView找
APIView里边有

  • def dispatch()

  ···/site-packages/rest_framework/views.py APIView  def dispatch()

 1     def dispatch(self, request, *args, **kwargs):
 2         ···
 3         # 在这对request做了一下加工
 4         request = self.initialize_request(request, *args, **kwargs) # -->> 对应步骤4、5  -->> 对应步骤4、5
 5         ···
 6         # request是丰富后的新request
 7         self.initial(request, *args, **kwargs) # -->> 对应步骤6、7、8、9  -->> 对应步骤6、7、8、9
 8         ···
 9         # 根据请求反射取属性,根据method做分发
10         handler = getattr(self, request.method.lower(),
11                                   self.http_method_not_allowed)
12         response = handler(request, *args, **kwargs)
  • initialize_request()

  initialize_request() ···/site-packages/rest_framework/views.py

 1     def initialize_request(self, request, *args, **kwargs):
 2         """
 3         Returns the initial request object.
 4         原始request进来,出去是 含request在内的大元祖
 5         request基础上增加了parsers、authenticators、negotiator、parser_context四个属性
 6         四个属性又对应着四个方法,点击方法进入查看
 7         """
 8         parser_context = self.get_parser_context(request)
 9         
10         # 把原始的request参数丰富了,利用的是Request类实例化        
11         return Request(
12             request,
13             parsers=self.get_parsers(),
14             authenticators=self.get_authenticators(), #获取用户认证类
15             negotiator=self.get_content_negotiator(),
16             parser_context=parser_context
17         )
  • Request()

  Request() ···\site-packages\rest_framework\request.py

 1 class Request(object):
 2     def __init__(self, request, parsers=None, authenticators=None,
 3                  negotiator=None, parser_context=None):
 4         ···
 5         self._request = request  #原始request的调用方式
 6         self.parsers = parsers or ()
 7         self.authenticators = authenticators or ()
 8         self.negotiator = negotiator or self._default_negotiator()
 9         self.parser_context = parser_context
10         self._data = Empty
11         self._files = Empty
12         self._full_data = Empty
13         self._content_type = Empty
14         self._stream = Empty
15     # 以上是封装的参数
16     # 此外,还封装了很多方法,一些加了@property
17     # 先看涉及到的parsers、authenticators、negotiator、parser_context 对应的方法
18 
19     def get_parsers(self):
20         """
21         Instantiates and returns the list of parsers that this view can use.
22         """
23         return [parser() for parser in self.parser_classes]
24 
25     def get_authenticators(self):
26         """
27         Instantiates and returns the list of authenticators that this view can use.
28         在这把用户认证类(对象)娶到手了
29         """
30         return [auth() for auth in self.authentication_classes]
31 
32 
33     def get_content_negotiator(self):
34         """
35         Instantiate and return the content negotiation class to use.
36         """
37         if not getattr(self, '_negotiator', None):
38             self._negotiator = self.content_negotiation_class()
39         return self._negotiator
40 
41     def get_parser_context(self, http_request):
42         """
43         Returns a dict that is passed through to Parser.parse(),
44         as the `parser_context` keyword argument.
45         """
46         # Note: Additionally `request` and `encoding` will also be added
47         #       to the context by the Request object.
48         return {
49             'view': self,
50             'args': getattr(self, 'args', ()),
51             'kwargs': getattr(self, 'kwargs', {})
52         }
class Request(object)
  • dispatch()到 initial()

APIView类中:

    def initial(self, request, *args, **kwargs):
        self.perform_authentication(request) # 调用认证的方法
  • initial()到perform_authentication()

APIView类中:

    def perform_authentication(self, request):
        # 只有这一句
        request.user

认证走到这了,只有一行request.user 说明是user方法里做的认证
此时request 是新的request 也就是Request() 实例化出来的对象
 进去 Request() 找user方法 看看干了啥
 从APIView() 跳到 Request() 里边了

  • Request() -- user()方法

    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                # 执行当前类的_authenticate() 方法
                self._authenticate()
        return self._user
  • user() 跳到 _authenticate()

  Request() -- _authenticate()方法

    def _authenticate(self):
        # 循环认证所有的类
        for authenticator in self.authenticators:
            try:
                # authenticators是上边4、5两步取出来的 用户认证类对象 列表
                # authenticator对象由用户认证类实例化而来,用户认证类肯定要支持authenticate()方法
                # 这个方法就是给我们留的钩子呀,藏得真TM深
                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()

 

整个探索过程中最重要的是,搞清楚类之间的继承和引用关系,以及不同类包含相同方法时,到底要执行哪个类。

遇到实在分不清的,可以打断点看它到底走的哪。不过打断点的前提是对程序整体流程有所了解

 

posted on 2018-01-30 23:06  robgo  阅读(154)  评论(0编辑  收藏  举报