由于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。
如果你没有配置认证类,其实它会走默认的认证类。
老规矩,关于配置认证类时依旧是先用局部的,再用全局的,最后是用默认的,如果你的上面的源码确实有感觉了的话,应该能够看懂。