drf之jwt傻瓜式啟動說明書
DRF之jwt使用說明書
jwt介紹
JsonWebToken
如何獲取token
先建立一張使用者表,要想使用jwt,必須使用django自帶的使用者表
-
在models.py中寫一個使用者類,匯入、繼承AbstractUser
-
在Terminal中做資料庫遷移,createsuperuser建立超級使用者
-
在路由中匯入jwt的模組
# urls.py from django.urls import path, include,re_path from rest_framework_jwt.views import obtain_jwt_token from api import views urlpatterns = [ path('loginView/', views.Login.as_view()), re_path(r"^login/", obtain_jwt_token) # login觸發jwt的檢視函式 ]
-
向login傳送post請求,請求體中加上username,password(這取決於使用者表中的欄位名),只需要且只能用這兩個來認證
-
得到響應,響應中就是token
這裡就得到了token,這個token有預設的過期時間,把它放在請求頭可以用來做登陸認證
自定義認證
前端完成登陸,獲取了token,放在請求頭中傳送給後端,後端接收並進行驗證
如果使用jwt內建的認證方法,預設會把你header裡token分開為兩段,第一段是 JWT
第二段是token,jwt會拿第二段去認證
注:登入介面需要做 認證 + 許可權 兩個區域性禁用
# auth.py from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication from rest_framework_jwt.authentication import jwt_decode_handler from rest_framework import exceptions class MyToken(BaseJSONWebTokenAuthentication): # 繼承jwt的方法,重寫authenticate def authenticate(self, request): jwt_value = str(request.META.get('HTTP_AUTHORIZATION')) # 從請求頭中取出token:http會自動把前端的authorization變成大寫,加上HTTP_字首 try: payload = jwt_decode_handler(jwt_value) # 使用繼承的類中的方法取token中的payload,驗證 print(payload) except Exception: raise exceptions.AuthenticationFailed("認證失敗") user = self.authenticate_credentials(payload) return user, None # 認證成功,返回使用者物件,這時就可以在檢視中任意位置取payload中給的資訊了
# views.py from rest_framework.views import APIView from rest_framework.response import Response from utils.auth import MyToken class Login(APIView): authentication_classes = [MyToken,] # 區域性使用,配置認證類。如果要全域性使用,去setting中配置 def get(self,request): return Response("Login")
使用內建的認證
內建的jwt前端使用格式是這樣
訪問需要登陸認證後才能訪問的url時,在請求頭(Header)中新增 Authorization:JWT <your_token> (Authorization 為 name,JWT <your_token> 為 value)
後端使用jwt內建的認證方式,僅需匯入兩個模組配置一下就可以了
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
# 認證模組
from rest_framework.permissions import IsAuthenticated
# 許可權模組
from utils.auth import MyToken
class Login(APIView):
authentication_classes = [JSONWebTokenAuthentication,]
permission_classes = [IsAuthenticated]
# 配置認證和許可權
def get(self,request):
return Response("Login")
注意,使用內建的認證方法,必須認證和許可權一起使用才能有效,只使用一個認證不用許可權,也可以訪問到介面
控制返回的資料格式
控制登陸介面返回的資料格式,讓obtain_jwt_token不止返回一個“token”,重寫整個登陸介面,或使用原有的登陸介面,改一些配置
第一種方法,改配置
在jwt的配置檔案中有個屬性
'JWT_RESPONSE_PAYLOAD_HANDLER':'rest_framework_jwt.utils.jwt_response_payload_handler',
控制返回資料的格式,我們只要重寫jwt_response_payload_handler的返回值,配置進去就可以控制返回的資料格式了
# setting.py 或者任意別的能先於jwt執行到的地方
from api.utils
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':'api.utils.my_jwt_response_payload_handler'
}
# utils.py
def my_jwt_response_payload_handler(token,user=None,request=None):
return {
'token':token,
'status':200,
'msg':'登陸成功'
}
自定義基於jwt的認證類
兩種寫法
# auth.py
# 第一種,基於BaseAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler # 跟上面是一個
import jwt
from api import models
class MyJwtAuthentication(BaseAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
# jwt提供了通過三段token,取出payload的方法,並且有校驗功能
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('簽名過期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('使用者非法')
except Exception as e:
# 所有異常都會走到這
raise AuthenticationFailed(str(e))
# 因為payload就是使用者資訊的字典
print(payload)
# return payload, jwt_value
# 需要得到user物件,
# 第一種,去資料庫查
# user=models.User.objects.get(pk=payload.get('user_id'))
# 第二種不查庫
user=models.User(id=payload.get('user_id'),username=payload.get('username'))
return user,jwt_value
# 沒有值,直接拋異常
raise AuthenticationFailed('您沒有攜帶認證資訊')
第二種
# 基於BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
#jwt提供了通過三段token,取出payload的方法,並且有校驗功能
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('簽名過期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('使用者非法')
except Exception as e:
# 所有異常都會走到這
raise AuthenticationFailed(str(e))
user=self.authenticate_credentials(payload)
return user,jwt_value
# 沒有值,直接拋異常
raise AuthenticationFailed('您沒有攜帶認證資訊')
在檢視中使用authentication_classes = [MyJwtAuthentication,]
匯入使用