drf 认证校验及源码分析 (2)

   由于modelViewSet继承自APIView,所以我们直接看as_view(),在下面这一句代码中,将会对request进行二次封装。

def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) # 这里 self.request = request self.headers = self.default_response_headers # deprecate?

   在二次封装中,实例化出了一个Request对象并返回了,在实例化时,会调用self.get_authenticators()方法,此时的self是我们自定义的视图类,切记这一点。

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(), # 看这里,获取认方式 negotiator=self.get_content_negotiator(), parser_context=parser_context )

   下面是get_authenticators()的代码,可以看见它会循环self.authentication_classes这个可迭代对象,如果你没有传递这个可迭代对象,那么该对象是一个默认的设置。

def get_authenticators(self): return [auth() for auth in self.authentication_classes] # ( authLogin.LoginVerify调用,实例化 )

   如果没有传递,将会找到APIView中的默认设置:

class APIView(View): renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES parser_classes = api_settings.DEFAULT_PARSER_CLASSES authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES # 默认的设置,默认的认证类,可以自己看一下

   如果有进行传递,可以发现它是使用了一个括号,这就代表会调用,由于传入的是一个类,所以它会进行实例化。

   所以我们可以认为request.authenticators这个参数是一个tuple,里面包含了认证类的实例化对象。

   然后,request就被二次包装完毕了。接下来执行 self.initial(),现在的self依然是我们自定义的视图类。

def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs)

   下面是self.inital()的代码,

def initial(self, request, *args, **kwargs): self.format_kwarg = self.get_format_suffix(**kwargs) self.perform_authentication(request) # 只看这个,认证相关的 self.check_permissions(request) self.check_throttles(request)

   到了self.perform_authentication()时,它传递进了个request,并且会去找user这个属性抑或是被property装饰的方法,所以我们需要到Request这个类中去找,需要注意的是如果user是一个方法,这代表会自动传递进self,此时的self则是我们经过二次封装的request对象。

   可以发现它是一个被装饰的方法。很显然我们没有_user这个方法或属性,会执行with语句,其实直接看self._authenticate()即可。再次强调,此次的self是二次封装的request对象。

@property def user(self): if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user

   下面是整个代码的核心。

def _authenticate(self): for authenticator in self.authenticators: # 循环认证类对象 ( authLogin.LoginVerify的实例化 ) try: user_auth_tuple = authenticator.authenticate(self) # 这里会找authenticate方法并将request对象进行传递,我们的认证类继承了BaseAuthentication这个类,它会实现一个接口方法, 但会抛出异常。 except exceptions.APIException: # 如果没有实现接口方法,或在验证时抛出异常都会被这里捕获 self._not_authenticated() # 执行这里 self.user将会是匿名用户AnonymousUser,而self.auth则是None raise if user_auth_tuple is not None: # 如果返回的值不是空 self._authenticator = authenticator self.user, self.auth = user_auth_tuple # 分别赋值给self.user,以及self.auth中 return # 返回 self._not_authenticated() # 上面有认证对象就会return,没有还是设置匿名用户和None 最后总结

   其实看了源码后,你可以发现我们的认证类可以不继承BaseAuthentication,但是推荐继承会更规范,因为这个基类实现了抽象接口。

   其次,它将返回的两个值分别赋值给了request.user以及request.auth。

   如果你没有返回值,那么对应的,request.user就是匿名用户,request.auth就是None。

   如果你没有配置认证类,其实它会走默认的认证类。

   老规矩,关于配置认证类时依旧是先用局部的,再用全局的,最后是用默认的,如果你的上面的源码确实有感觉了的话,应该能够看懂。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyswxd.html