用戶驗證用戶是否合法登錄。
部份內容在DRF視圖的使用及源碼流程分析講解,建議先看講解視圖的這篇文章。html
認證使用的方法流程以下:python
BaseAuthentication
,而且覆寫其authenticate
方法。不繼承BaseAuthentication
也能夠,但認證類中必須聲明authenticate
和authenticate_header
兩個方法。request.user
這個屬性中,第二個值將會傳遞給request.auth
這個屬性中。APIException
或者AuthenticationFailed
,它會自動捕獲並返回。自定義認證類:app
完成一、二、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步:源碼分析
局部認證:spa
在一個須要認證的CBV裏面,添加authentication_classes
類屬性。如:3d
class UserAPIView(GenericAPIView, ListModelMixin): authentication_classes = [MyAuthentication] queryset = User.objects serializer_class = UserSerializer
全局認證:rest
在settings.py
裏面設置:code
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["libs.MyAuth.MyAuthentication"] }
在源碼分析部分,你們將會明白爲什麼這樣設置。jwt
認證的執行,是發生在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 = []