目錄
一、BaseAuthentication - 用於攔截請求,在視圖函數錢執行相應認證方法
1-1 登陸相關視圖函數 - 使用Token字符串存儲數據庫模擬session
1-2 BaseAuthentication 登陸認證 - drfAuth.py
二、認證配置 - authentication_classes
一、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()