一、認(rèn)證的流程
- 首先我們采用的cbv的模式去寫饼拍。去看以下加工后的request里面包含了什么不同?
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
class DogView(APIView):
def get(self, request, *args, **kwargs):
return HttpResponse('獲取狗!')
def post(self, request, *args, **kwargs):
return HttpResponse('更新狗')
其實(shí)APIView繼承的是Django的View,只不過又在此基礎(chǔ)上又豐富了一些兰吟。那么現(xiàn)在帶大家來看一下源碼!
基于CBV的寫法茂翔,那么當(dāng)我們?cè)L問接口url的時(shí)候混蔼,那么首先執(zhí)行的是dispath方法。
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
## 對(duì)原生的request進(jìn)行加工(豐富了一些功能)
request = self.initialize_request(request, *args, **kwargs)
# request._request 獲取原生request
# request.authenticators 獲取認(rèn)證類的對(duì)象
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:
# 此處利用了Python的反射函數(shù)
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
其中有一行是對(duì)原生的request進(jìn)行加工珊燎,那么initialize_request函數(shù)又做了什么惭嚣?
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料按。那么它又調(diào)用了get_authenticators(),
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
# 使用了列表生成式,那么我們得到的是一個(gè) 對(duì)象的list卓箫。
return [auth() for auth in self.authentication_classes]
那么self.authentication_classes 又是什么呢载矿?
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
從代碼可知,這是django的配置文件里提供的DEFAULT_AUTHENTICATION_CLASSES
那么現(xiàn)在我們已經(jīng)知道: request里已經(jīng)包含了最初的request(request._request), 以及認(rèn)證后的對(duì)象[], (request.authenticators)
- 接下來到了try語句里面:
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)
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
此時(shí)又調(diào)用了request.user, 因?yàn)閹аb飾符逢勾,所以以屬性的方法調(diào)用牡整,而此時(shí)self指的是Request的實(shí)例,
@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
此時(shí)又調(diào)用了_authenticate方法
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
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()
各位同學(xué)溺拱,還記得authenticators這個(gè)么逃贝? 這個(gè)就是認(rèn)證對(duì)象的list,那么從代碼可知迫摔,我們的這個(gè)對(duì)象包含一個(gè)authenticate方法沐扳,所以所以所以我們自己定義的時(shí)候,就主要是定義這個(gè)方法句占!
哇喔;ι恪!纱烘! 整體步驟我們理清了杨拐,那么如何來完成一個(gè)只有登錄之后才可以訪問的接口api呢。
二擂啥、實(shí)現(xiàn)
self.authentication_classes 當(dāng)我們類提供authentication_classes這個(gè)屬性時(shí)哄陶,那么就不會(huì)讀取配置文件默認(rèn)的。
再來看以下代碼:
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions
class MyAuthentication(object):
def authenticate(self, request):
token = request._request.GET.get('token')
if not token:
raise exceptions.AuthenticationFailed('用戶認(rèn)證失敗')
return ('alex', None)
def authenticate_header(self, val):
pass
class DogView(APIView):
authentication_classes = [MyAuthentication, ]
def get(self, request, *args, **kwargs):
return HttpResponse('獲取狗!')
def post(self, request, *args, **kwargs):
return HttpResponse('更新狗')
現(xiàn)在明白怎么回事了么啤它? MyAuthentication類里面的authenticate_header這個(gè)函數(shù)雖然是空的代碼奕筐,但是是強(qiáng)制要寫的~ 至于為什么舱痘, tell me why变骡?
歡迎大家一起找我探討Python的代碼,前一段時(shí)間因?yàn)楣緦?shí)在是太忙了芭逝,所以更新不太及時(shí)塌碌,各位請(qǐng)見諒~~~~~