一、认证源码流程
1、认证准备工作
在rest framework之APIView中提到过rest framework的视图不仅有CBV分发的特性,而且又对request进行了封装,其中封装的就有认证功能。在APIView类下的dispatch方法中:
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 #rest-framework重构request对象 request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) # Get the appropriate handler method #这里和CBV一样进行方法的分发 if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
在dispatch方法中:
request = self.initialize_request(request, *args, **kwargs)
是重构request对象,initialize_request返回的就是一个request对象,封装了原request以及认证相关:
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, #传入原request parsers=self.get_parsers(), authenticators=self.get_authenticators(), #认证相关 negotiator=self.get_content_negotiator(), parser_context=parser_context )
在request对象中封装了authenticators这一个个写好的认证类的对象,可以自己配置的认证类,这样认证的准备工作已经完成了(其实就是request封装认证类对象的列表)。
2、认证过程
在dispatch方法中的代码中:
self.initial(request, *args, **kwargs) #request是已经重构的request
在initial方法中:
def initial(self, request, *args, **kwargs): ... # Ensure that the incoming request is permitted self.perform_authentication(request) #进行认证 self.check_permissions(request) self.check_throttles(request)
在perform_authentication方法中:
def perform_authentication(self, request): """ Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication will instead be performed lazily, the first time either `request.user` or `request.auth` is accessed. """ request.user
执行的是request.user,此时引出了之前准备工作的request封装对象
#方便寻找,导入 from rest_framework.request import Request
@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
在_authenticate方法中
def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ """ 三种情况: 1、正常的认证,元组不为空 2、认证失败,没有通过认证类中认证方法的检验,没有登陆 3、匿名用户,认证类中认证方法没有检验,返回的是None """ for authenticator in self.authenticators: #循环取出每一个认证类的对象 try: 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() #匿名用户执行
def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None. """ self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() #在settings中可以设置默认的 else: self.user = None #如果settings中没设置默认的就执行 if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None