認證
前言
用戶驗證用戶是否合法登陸,
部分內容在DRF視圖的使用及原始碼流程分析講解,建議先看講解視圖的這篇文章,
使用流程
認證使用的方法流程如下:
- 自定義認證類,繼承
BaseAuthentication,并且覆寫其authenticate方法,不繼承BaseAuthentication也可以,但認證類中必須宣告authenticate和authenticate_header兩個方法, - 當認證通過后應該回傳兩個值(一個元組),并且第一個值會傳遞給
request.user這個屬性中,第二個值將會傳遞給request.auth這個屬性中, - 如果認證失敗,則拋出例外
APIException或者AuthenticationFailed,它會自動捕獲并回傳, - 當前認證類設定是全域使用還是區域使用,
自定義認證類:
完成1、2、3步,例外統一回傳
AuthenticationFailed,
import jwt
from jwt import exceptions
import rest_framework.exceptions as rest_exception
from rest_framework.authentication import BaseAuthentication
from rest_framework import status
from app1.models import Login
from libs.TokenManager import SALT
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.META.get("HTTP_TOKEN") # 在請求頭中設定token值,獲取的是HTTP_TOKEN
if not token:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="請在請求頭中設定token值!")
try: # 決議token
verified_payload = jwt.decode(token, SALT, "HS256")
user_id, username = verified_payload["user_id"], verified_payload["username"]
user = Login.objects.filter(user=user_id, token=token).first()
if user:
return user_id, username
else:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="用戶不存在!")
except exceptions.ExpiredSignatureError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token已經失效!")
except jwt.DecodeError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token認證失敗!")
except jwt.InvalidTokenError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token非法!")
第4步:
區域認證:
在一個需要認證的CBV里面,添加authentication_classes類屬性,如:
class UserAPIView(GenericAPIView, ListModelMixin):
authentication_classes = [MyAuthentication]
queryset = User.objects
serializer_class = UserSerializer
全域認證:
在settings.py里面設定:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["libs.MyAuth.MyAuthentication"]
}
在原始碼分析部分,大家將會明白為何這樣設定,
原始碼分析
認證的執行,是發生在dispatch函式的程序中,

值得注意的是,封裝request的時候,我們的指定的認證類也會一起封裝在新的request里面,
接下來看看
get_authenticators的執行,
使用串列生成式挨個實體化了每個authentication_classes里面的認證類,而
authentication_classes讀取了我們自定義的認證類,注:
如果是區域認證,那么就是我們直接給
authentication_classes賦值如果是全域認證,那么就是讀取我們
settings中的DEFAULT_AUTHENTICATION_CLASSES配置項,
之后,在initial函式中,執行了三大驗證,其中就有認證,

而認證直接執行了request.user,它其實是一個被@property裝飾的方法,

接下來的操作都是在rest_framework.request模塊里面,新封裝的request就是這下面的Request類的實體,

當沒有_user屬性的時候,說明還未認證,則會執行 _authenticate() 方法

- 認證成功,回傳元組,
- 認證失敗,執行
_not_authenticated,
補充
最后,一個問題,當配置了全域認證以后,之后每個介面的訪問都要執行認證,而有的借口并不需要認證或者認證的類不一樣(如登陸介面),該怎么辦呢?
其實很好辦,全域設定以后并不影響區域設定的生效,因為區域設定的優先級大于全域設定,就比如對于登陸介面來說,我們只需要在登陸介面CBV中設定authentication_classes為空就可以了,如果有特殊需要,也可以指定其他認證類,
class LoginAPIView(APIView):
authentication_classes = []
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/242692.html
標籤:Python



