drf 认证 权限 节流 源码流程

调用dispatch方法,从IndexView视图开始寻找,自身不存在则寻找APIview,APIview中存在则停止,即调用APIview中的dispatch方法

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
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

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
View中的dispatch

def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
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
return handler(request, *args, **kwargs)

其中两个重要操作是

request = self.initialize_request(request, *args, **kwargs)
self.initial(request, *args, **kwargs)

initialize_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(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)

这里其实是返回了一个Request的对象,该对象封装了原有的request,还有重要的一点是authenticators

request原对象被赋值给了Request._request属性而authenticate是从get_authenticators()这个方法中获取到的

而这个返回的Request对象赋值给了调用dispatch的视图 self.request了。

initial

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) # 频率验证

认证authenticate
正常执行as_view(),返回dispatch后,访问URL执行dispatch方法,用反射的方法去执行对应类视图中的方法。

perform_authentication
认证其实就是initial中的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已经不是原request了,dispatch将Request赋值给了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

def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
# authenicators已经在initialize_request方法中给self定义过了
try:
user_auth_tuple = authenticator.authenticate(self) # 执行认证类中的方法 认证
except exceptions.APIException:
self._not_authenticated() # 报错就执行这个方法
raise

if user_auth_tuple is not None: # 如果上面认证方法返回的不是none
self._authenticator = authenticator # 把认证的类给赋值给self
self.user, self.auth = user_auth_tuple # 然后把认证返回后的元组 一个user 一个auth
return

self._not_authenticated()

return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
从上面的initialize_request中讲到在定义Request对象的时候传入的authenticate,可以看到,他是调用了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]

权限permission
流程
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self): # has_permission 权限认证方法
# 如果到这里就是权限认证返回False 也就是没通过
self.permission_denied( #
request, message=getattr(permission, 'message', None)

def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
return [permission() for permission in self.permission_classes]

class IndexView(APIView):
authentication_classes = [MyAuthentication]
permission_classes = [MyPermission]

def get(self, request, *args, **kwargs):
ret = {
"content": "index ok",
"code": 200,
"token": request.auth.token
}
return JsonResponse(ret)

频率throttles

def check_throttles(self, request):
"""
Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
"""
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait())
用get_throttles方法去获取指定类,然后执行allow_request方法

posted @ 2019-11-25 08:16  边城bei  阅读(247)  评论(0)    收藏  举报