DRF认证之源码详解
一. DRF认证之源码详解
-
dispatch()源码执行流程详解
客户端所有的请求到来之后都会执行dispatch()方法,dispatch()方法会根据不同的请求方式,从而触发不同的方法,如GET/POST/PUT/DELETE/UPDATE等方法.
-
第一步对
request
进行封装(添加数据)
request = self.initialize_request(request, *args, **kwargs) -
第二步:initial(request, *args, **kwargs):
#处理版权信息
#认证
#权限
#请求用户进行访问频率的限制 -
第三步,执行:get/put/post/delete函数
handler(request, *args, **kwargs)
-
第四步,对返回结果再次进行加工
self.response = self.finalize_response(request, response, *args, **kwargs)
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进行封装(添加数据) 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 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 #第三步,执行:get/put/post/delete函数 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
-
接下来对每一步进行详解:
-
第一步对request进行封装(添加数据)
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(), # 解析数据,默认有三种方式,可点进去看 #self.get_authenticators() 先找自己的,没有就找父类的 authenticators=self.get_authenticators(),#获取认证相关的所有数据并实例化,传入request对象并供request使用 negotiator=self.get_content_negotiator(), parser_context=parser_context )
-
获取认证相关的类具体 authenticators=self.get_authenticators()
def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ #返回一个对象列表 return [auth() for auth in self.authentication_classes]
-
查看认证相关的self.authentication_classes
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #默认的
-
接着点击api_settings
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) #接着点击继承的DEFAULTS #这时候就找到了 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication'
-
导入SessionAuthentication、BasicAuthentication类:
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import BasicAuthentication
-
看看
authenticate
,authenticate_header
两个方法class BaseAuthentication: """ All authentication classes should extend BaseAuthentication. """ def authenticate(self, request): """ Authenticate the request and return a two-tuple of (user, token). """ raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass
第二步:查看self.initial(request, *args, * *kwargs):
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
#处理版本信息
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
#认证
self.perform_authentication(request)
#权限
self.check_permissions(request)
#限流
self.check_throttles(request)
- 点击看一下认证的self.perform_authentication(request):
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已经是加工后的request了
- 看一下
request.user
这个属性
@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 #返回user
- 执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
#循环对象列表
for authenticator in self.authenticators:
try:
#执行每一个对象的authenticate方法
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 #返回一个元组,user,和auth,赋给了self,
# 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
return
self._not_authenticated()
-
在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法
如果用户没有认证成功:self._not_authenticated()
def _not_authenticated(self):
"""
Set authenticator, user & authtoken representing an unauthenticated request.
Defaults are None, AnonymousUser & None.
"""
#如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None #
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
else:
self.user = None # None 表示跳过该认证
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN() # 默认值为:None
else:
self.auth = None
# (user, token)
# 表示验证通过并设置用户名和Token;
第三步:执行GET/POST/PUT/DELETE等方法
第四步:对第三步返回结果进行加工