認證的實作
使用步驟:
# 通過認證類完成,使用步驟
1 寫一個認證類,繼承BaseAuthentication
2 重寫authenticate方法,在內部做認證
3 如果認證通過,回傳2個值
4 認證不通過拋AuthenticationFailed例外
5 只要回傳了兩個值,在后續的request.user 就是當前登錄用戶
認證原始碼分析:
#1 APIVIew----》dispatch方法---》self.initial(request, *args, **kwargs)---->有認證,權限,頻率
#2 只讀認證原始碼: self.perform_authentication(request)
#3 self.perform_authentication(request)就一句話:request.user,需要去drf的Request物件中找user屬性(方法)
#4 Request類中的user方法,剛開始來,沒有_user,走 self._authenticate()
#5 核心,就是Request類的 _authenticate(self):
def _authenticate(self):
# 遍歷拿到一個個認證器,進行認證
# self.authenticators配置的一堆認證類產生的認證類物件組成的 list
#self.authenticators 你在視圖類中配置的一個個的認證類:authentication_classes=[認證類1,認證類2],物件的串列
for authenticator in self.authenticators:
try:
# 認證器(物件)呼叫認證方法authenticate(認證類物件self, request請求物件)
# 回傳值:登陸的用戶與認證的資訊組成的 tuple
# 該方法被try包裹,代表該方法會拋例外,拋例外就代表認證失敗
user_auth_tuple = authenticator.authenticate(self) #注意這self是request物件
except exceptions.APIException:
self._not_authenticated()
raise
# 回傳值的處理
if user_auth_tuple is not None:
self._authenticator = authenticator
# 如何有回傳值,就將 登陸用戶 與 登陸認證 分別保存到 request.user、request.auth
self.user, self.auth = user_auth_tuple
return
# 如果回傳值user_auth_tuple為空,代表認證通過,但是沒有 登陸用戶 與 登陸認證資訊,代表游客
self._not_authenticated()
認證組件的使用:
1.models.py中撰寫模型類
# 用戶表
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
def __str__(self):
return self.username
# 用戶登錄記錄表
# 如何區分用戶是否登錄了?
class UserToken(models.Model):
# SET_NULL SET_DEFAULT CASCADE SET(函式記憶體地址)
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
token = models.CharField(max_length=32, null=True) # 用戶如果沒有登錄,就是空,如果登錄了,就有值,登錄多次以最后一次為準
2.views.py中判斷登錄資訊
class UserView(ViewSet):
authentication_classes = []
@action(methods=['POST', ], detail=False, url_path='login')
def login(self, request):
# 取出前端傳入的用戶名密碼,校驗,通過,回傳登錄成功,失敗就回傳用戶名密碼錯誤
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:
# 登錄成功,不同人生成的token是不一樣的,誰登錄的,就把token存到UserToken表中
token = str(uuid.uuid4()) # 生成一個永不重復的隨機字串
# 存UserToken:如果沒有記錄,就是新增,如果有記錄更新一下即可
# 通過user去UserToken表中查資料,如果能查到,使用defaults的資料更新,如果查不到,直接通過user和defaults的資料新增
UserToken.objects.update_or_create(defaults={'token': token}, user=user)
# 作用是為了添加資料時防止重復. 先去查詢, 如果沒有在創建, 如果有則更新.
return Response({'code': 100, 'msg': '登錄成功', 'token': token})
else:
return Response({'code': 101, 'msg': '用戶名或密碼錯誤'})
# 在app中寫一個認證類 app_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
# 認證邏輯,如果認證通過,回傳兩個值
#如果認證失敗,拋出AuthenticationFailed例外
token=request.GET.get('token')
if token:
user_token=UserToken.objects.filter(token=token).first()
# 認證通過
if user_token:
return user_token.user,token
else:
raise AuthenticationFailed('認證失敗')
else:
raise AuthenticationFailed('請求地址中需要攜帶token')
# 可以有多個認證,從左到右依次執行
# 全域使用,在setting.py中配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
# 區域使用,在視圖類上寫
authentication_classes=[MyAuthentication]
# 區域禁用
authentication_classes=[]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518473.html
標籤:Python
上一篇:JAVA設計模式-代理模式
