05 drf源码剖析之认证
05 drf源码剖析之认证
1. 认证简述
-
当我们通过Web浏览器与API进行交互时,我们可以登录,然后浏览器会话将为请求提供所需的身份验证。
-
如果我们以编程方式与API进行交互,则需要在每个请求上显式提供身份验证凭据。
-
如果我们尝试在不进行身份验证的情况下创建代码段,则会收到错误消息
2. 认证的使用
-
创建一个认证类MyAuthentication
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: return (user_object,token) return (None,None) # 最好继承Base类有一个约束
-
在需要认证的类添加authentication_classes
class OrderView(APIView): authentication_classes = [MyAuthentication, ] def get(self,request,*args,**kwargs): print(request.user) print(request.auth) return Response('order') class UserView(APIView): authentication_classes = [MyAuthentication,] def get(self,request,*args,**kwargs): print(request.user) print(request.auth) return Response('user')
-
全局使用配置,修改匿名用户的名称
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES":["utils.auth.GeneralAuthentication",], # 在全局使用认证类,列表里边写认证类的路径,不需要在类内部定义类 "UNAUTHENTICATED_USER":None, # 修改匿名用户的昵称 "UNAUTHENTICATED_TOKEN":None }
3. 源码剖析
-
请求过来先执行dispatch方法
def dispatch(self, request, *args, **kwargs): """ - 内部封装了 authenticators = [MyAuthentication(), ] """ request = self.initialize_request(request, *args, **kwargs)
-
执行initialize_request方法,将认证对象列表封装到新的request对象中
def initialize_request(self, request, *args, **kwargs): 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 )
-
执行get_authenticators方法,将认证类实例化成对象放到认证列表中
def get_authenticators(self): return [ auth() for auth in self.authentication_classes ]
-
认证时会执行Request对象的user方法
class Request: def __init__(self, request,authenticators=None): self._request = request self.authenticators = authenticators or () @property def user(self): if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user
-
_authenticate方法会执行每个认证类的authenticate方法
def _authenticate(self): 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()
-
认证成功后,将用户对象赋值给request.user
@user.setter def user(self, value): self._user = value self._request.user = value
4. 总结
- 当用户请求过来时,执行dispatch,通过initialize_request方法,
- 找到认证的所有类并实例化成对象列表,然后将对象列表封装到新的request对象中。
- 执行下面的initial方法,经过认证的request.user方法
- 在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,返回值有三种,①抛出异常②返回None③返回一个元组
- 返回元组的两个值分别赋值给request.user和request.auth