rest_framework學習之認證

在講reat_frameworkd的認證前,我們先來看看Django原生的類視圖(django.views.View)的運行過程是怎麼樣的:

wwsgi --> 中間件(Middleware) -->url路由解析 --> 類視圖的as_view方法 --> view方法 --> dispath方法 --> 反射對應的請求方法的函數並執行

一、 在rest_framework中提供了APIView,重寫了View的dispatch方法,我們可以從源碼中看出,在執行dispath方法的時又執行了initial方法,對請求進行了認證、權限驗證、節流等方法:
def initial(self, request, *args, **kwargs):
	self.format_kwarg = self.get_format_suffix(**kwargs)
	neg = self.perform_content_negotiation(request)
	request.accepted_renderer, request.accepted_media_type = neg
	#版本解析
	version, scheme = self.determine_version(request, *args, **kwargs)
	request.version, request.versioning_scheme = version, scheme
	# 認證
	self.perform_authentication(request)
	# 權限
	self.check_permissions(request)
	# 節流
	self.check_throttles(request)
二、 認證步驟中執行了perform_authentication方法進而又執行了request(在原生的request上裝飾過的)的user方法:
def perform_authentication(self, request):
	request.user
三、 接着運行了_authenticate方法
@property
def user(self):
	if not hasattr(self, '_user'):
		with wrap_attributeerrors():
			self._authenticate()  # 主要的認證函數
	return self._user
四、 在_authenticate方法中,將self.authenticators的每一個認證類進行實例化,並執行認證類的authenticate方法。當認證出錯時又執行self._not_authenticated方法。
def _authenticate(self):
	for authenticator in self.authenticators:  # 取出self.authenticators的每一個認證類
		try:
			user_auth_tuple = authenticator.authenticate(self)  # 執行認證類的authenticate方法
		except exceptions.APIException:
			self._not_authenticated()  # 認證失敗時執行_not_authenticated方法
			raise

		if user_auth_tuple is not None:
			self._authenticator = authenticator
			self.user, self.auth = user_auth_tuple
			return

	self._not_authenticated()
五、 self.authenticators是request的屬性,在執行APIView的dispatch方法時對原生的request封裝了你在類視圖中添加的authentication_classes屬性,遍歷並將它們存放在request的authenticators屬性中:
def dispatch(self, request, *args, **kwargs):
	"""部分內容省略"""
	request = self.initialize_request(request, *args, **kwargs)
  • APIView的initialize_request方法又實例化了Request對象,將解析、認證等信息封裝在request中,其中self.get_authenticators()就是封裝認證類的方法:
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(),  # 將認證類封裝到request的authenticators中()
		negotiator=self.get_content_negotiator(),
		parser_context=parser_context
	)
  • self.get_authenticators()方法簡單的將authentication_classes的每一個對象實例化並返回,賦值到authenticators中,Request會將認證類又賦值到self.authenticators中,供認證的時候使用:
def get_authenticators(self):
	return [auth() for auth in self.authentication_classes]
六、 authentication_classes在APIView類的屬性中出現,若繼承了APIView的自定義類中出現了authentication_classes,會取自定義的authentication_classes列表而不是APIView內置的。因此我們在爲視圖準備認證方法的時候,可以在類視圖中添加authentication_classes屬性,用列表的形式將需要視圖需要使用的認證類放在裏面:
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication, BasicAuthentication

class MyVIew(APIView):
	authentication_classes = [BaseAuthentication, BasicAuthentication]  # 使用了rest_framework內置的認證類
	…………

rest_framework內置了五種認證類:BaseAuthentication、BasicAuthentication、SessionAuthentication、TokenAuthentication、RemoteUserAuthentication。

七、 當然我們可以自定義認證類,然後把它們放在視圖的authentication_classes中,但是認證類必須包含兩個方法,即authenticate和authenticate_header:
from user.models import UserToken
from rest_framework import exceptions

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request._request.GET.get('token')
		try:
			usertoken = UserToken.objects.get(token=token)
		except UserToken.DoesNotExist:
			msg = _('請登錄後訪問')
			raise exceptions.AuthenticationFailed(msg)
			
		return usertoken.user, none
		
    def authenticate_header(self, request):
        pass

authenticate有返回的內容有三種情況:1. 返回一個元組(user, auth),代表認證成功,最終這兩個對象會賦值到request的user和auth中;2. 認證成功後返回(none, none),代表匿名訪問;3. 認證錯誤拋出異常AuthenticationFailed,可以定製message來指定認證失敗後的返回的信息。authenticate_header方法可以不填寫內容

八、 如果視圖中設置authentication_classes,則爲局部認證類,我們還可以爲整個項目設置全局認證,即在項目的settings.py中添加以下配置:
REST_FRAMEWORK = {
	# 以列表的形式,將視圖類的路徑填寫在AUTHENTICATION_CLASSES裏,這裏的認證類將影響所以視圖
    "AUTHENTICATION_CLASSES": ['rest_framework.authentication.BaseAuthentication']
}

當部分視圖需要使用其他的認證類時,可以在視圖添加authentication_classes屬性來覆蓋全局配置的視圖類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章