DRF 的 APIView 繼承 View
- django 的 View
- DRF 的 APIView
-
dispatch 中,對request進行加強
-
APIView 調(diào)用了 View 的 as_view 方法
view = super(APIView, cls).as_view(**initkwargs) -
View 調(diào)用了 APIView 的 dispatch 方法
self.dispatch(request, *args, **kwargs) -
dispatch 方法加強了原生 request
# 第一次的加強(添加方法) request = self.initialize_request(request, *args, **kwargs) # 第二次的調(diào)用(調(diào)用方法) self.initial(request, *args, **kwargs)
>>>源碼
>>> 第一次的加強(1)
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
# 對request進行了加強
return Request(
request, # Django原本的request
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), # 與認證相關(guān)
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
>>> 第一次的加強(2)
# 認證
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
# 讀配置
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
>>>第二次的調(diào)用(1)
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) # 認證 token / 匿名
self.check_permissions(request) # 權(quán)限 / 誰能訪問什么內(nèi)容
self.check_throttles(request) # 限流 60/分
>>> 第二次的調(diào)用(2)
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 # 驗證用戶身份方法
>>> 第二次的調(diào)用(3)
# rest_framework.request.py 文件內(nèi)
@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
- 我們可以寫一個自己的登錄認證
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
class MyAuthentication(BaseAuthentication):
def authenticate(self, request, *args, **kwargs):
if not request._request.GET.get('token') # 拿request 對象的屬性:
raise exceptions.AuthenticationFailed('認證失敗')
return ("海綿寶寶", None)
# views.py
class xxx(APIView):
authentication_classes = [MyAuthentication]
...
>>> 第二次的調(diào)用(4)
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
# 如果是自定義方法,調(diào)用自己的方法
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()
- tips:多認證(多個認同時滿足)
- 應(yīng)用場景:人臉識別、高級安全、資金提現(xiàn)