Django - DRF - BaseAuthentication 認證組件

目錄

一、BaseAuthentication - 用於攔截請求,在視圖函數錢執行相應認證方法

1-1 登陸相關視圖函數 - 使用Token字符串存儲數據庫模擬session

1-2 BaseAuthentication 登陸認證 - drfAuth.py

1-3 視圖函數

二、認證配置 - authentication_classes

2-1 局部配置

2-2 全局配置 及 局部禁用

三、相關源碼分析


一、BaseAuthentication - 用於攔截請求,在視圖函數錢執行相應認證方法

總結:

  • 認證類必須繼承 BaseAuthentication
    • from rest_framework.authentication import BaseAuthentication
  • 認證類內必須重寫 authenticate(self, request) 方法,request參數必須傳入
  • 若後續有其他認證類需要執行,必須返回空!!
  • 若後續不無其他認證類需要執行,則返回兩個值 - 對應DRF內Request對象User類內_authenticate方法執行
  • 認證失敗,拋出  exceptions.APIException 異常 
    • from rest_framework import exceptions
  • 執行認證的視圖類中配置 authentication_classes = [drfAuth.LoginAuth, ]

1-1 登陸相關視圖函數 - 使用Token字符串存儲數據庫模擬session

from rest_framework.views import APIView
import hashlib, time
from app01 import models
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse



def get_token(name):
    '''
    將當前時間戳轉化爲被hash的md5字符串
        - 注意:md5.update(內部必須插入bytes格式)
    :param name:
    :return:
    '''
    md5 = hashlib.md5()
    md5.update(str(time.time()).encode('utf-8'))
    md5.update(name.encode('utf-8'))
    return md5.hexdigest()


class Login(APIView):
    '''
    接收對應請求發送的數據,對其中的name和pwd進行校驗
        - 校驗通過:使用get_token(name)獲取一個當前唯一的字符串作爲token返回給前端,並且存入數據庫中
        - 校驗不通過:返回錯誤信息
    '''

    def post(self, request, *args, **kwargs):
        response = {'status': 100, 'msg': '登陸成功'}
        name = request.data.get('name')
        pwd = request.data.get('pwd')
        try:
            # 使用get獲取表內符合對象,如不存在則報錯
            user = models.UserInfo.objects.get(name=name, pwd=pwd)
            token = get_token(name)
            # update_or_create : 表內記錄的更新或創建
            models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
            response['token'] = token
        except ObjectDoesNotExist as e:
            response['status'] = 101
            response['msg'] = '用戶名密碼錯誤'
        except Exception as e:
            # 未知錯誤捕獲
            response['status'] = 101
            response['msg'] = str(e)
        return JsonResponse(response, safe=False)

1-2 BaseAuthentication 登陸認證 - drfAuth.py

from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework import exceptions
import datetime


class LoginAuth(BaseAuthentication):
    # authenticate必須在DRF認證內被重寫,request參數必須傳入
    def authenticate(self, request):
        '''
        將獲取的token去token表內進行比對,存在信息即驗證通過
            - 獲取token表內token更新時間,若超時則驗證失敗重新登陸(用於數據的清理)
            - 驗證通過:返回空 - 表示後續仍能繼續其他驗證
            = 驗證通過:返回認證用戶和當前數據記錄對象 - 後續不再進行驗證
                - 對應DRF內Request對象User類內_authenticate方法執行
                - from rest_framework.request import Request
        :param request:
        :return:
        '''
        # 數據放在header內傳輸,request.META獲取
        # meta查詢key值格式:HTTP_大寫字段名 例如:token - HTTP_TOKEN
        token = request.META.get('HTTP_TOKEN')
        # token = request.query_params.get('token')
        print(token)

        ret = models.UserToken.objects.filter(token=token).first()
        if not ret:
            # 查不到,拋異常
            raise exceptions.APIException('認證失敗,請重新登陸!')

        t = datetime.datetime.now() - ret.token_time
        print(t.total_seconds())
        # 若表內登陸時間超過10min則自動清除
        if t.total_seconds() > 600:
            ret.delete()
            raise exceptions.APIException('登陸超時,請重新登陸!')
        # 查詢到對應用戶信息,認證通過
        # 返回當前認證用戶,當前token記錄對象
        # 返回的數據可通過 request.user, request.auth進行獲取
        return ret.user, ret

1-3 視圖函數

from rest_framework.views import APIView
from django.http import JsonResponse
from app01 import MySerializer
from app01 import drfAuth

class Books(APIView):
    # 列表中,類名不能加括號
    authentication_classes = [drfAuth.LoginAuth, ]

    def get(self, request, *args, **kwargs):
        # 只要通過認證,就能取到當前登錄用戶對象
        print(request.user)
        response = {'status': 100, 'msg': '查詢成功'}
        ret = models.Book.objects.all()
        book_ser = MySerializer.BookSerializer(ret, many=True)
        response['data'] = book_ser.data
        return JsonResponse(response, safe=False)

二、認證配置 - authentication_classes

2-1 局部配置

'''
需認證類內配置
   !! 注意:可以在列表中存入多個認證類,但是存在返回值的認證類必須位於最後!!
'''
authentication_classes = [drfAuth.LoginAuth, ]

2-2 全局配置 及 局部禁用

'''
settings配置文件
    所有視圖內的類都會經過REST_FRAMEWORK內的認證類內認證
'''
REST_FRAMEWORK={
    'DEFAULT_AUTHENTICATION_CLASSES':['app01.drfAuth.LoginAuth',]
}

'''
某一個視圖類內禁用認證 
    - 認證規則首先使用當前類內的 authentication_classes 規則
    - 置空表示不執行任何認證
'''
authentication_classes = []

三、相關源碼分析

'''
DRF內 Request對象 User類內 _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
        # 若認證類存在返回值,並且符合self.user, self.auth返回規則,return跳出循環
		if user_auth_tuple is not None:
			self._authenticator = authenticator
			self.user, self.auth = user_auth_tuple
			return

	self._not_authenticated()	

 

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