drf中jwt應用

李瑞鑫發表於2024-04-22

第一步 在登入類中生成 jwt

class Login(MyException,APIView):
    def post(self,request):
        user_obj = models.UserInfo.objects.filter(**request.data).first()
        if not user_obj:
            return Response({"code":1001, "msg":"使用者名稱密碼錯誤"})
        # 生成jwt token並返回
        headers = {
            'typ': 'jwt',
            'alg': 'HS256'
        }
        # 構造payload
        payload = {
            'user_id': user_obj.id,  # 自定義使用者ID
            'username': user_obj.username,  # 自定義使用者名稱
            'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5)  # 超時時間
        }
        token = jwt.encode(payload=payload, key=settings.SECRET_KEY, algorithm="HS256", headers=headers)
        print("t:",token)
        return Response({"code":0, "msg":"登入成功", "token":token,"username":user_obj.username,"userid":user_obj.id})

第二步 在認證類中校驗 jwt合法性

  

class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
    token = request.query_params.get("token")
    if not token:
        raise AuthenticationFailed({"code":1002,"msg":"必須攜帶token"})
    # 2.合法性
    try:
        # print(token)
        verified_payload = jwt.decode(token, settings.SECRET_KEY, algorithms="HS256")
        print("v:",verified_payload)
        current_timestamp = int(datetime.datetime.now().timestamp())
        print(current_timestamp)
        print(verified_payload.get("exp"))
        #判斷是否需要更新jwt
        verified_payload["exp_time"] = verified_payload.get("exp") - current_timestamp
        # 獲取當前時間 vs 有效期
        return (verified_payload, token)
    except Exception as e:
        print(e)
        raise AuthenticationFailed("認證失敗")

第三步 寫一個更新jwt的類

class UpdateTokenView(ResView,APIView):
    authentication_classes = [MyAuthentication]

    def get(self, request):
        print("info:",request.user, request.auth)
        # 生成jwt token並返回
        headers = {
            'typ': 'jwt',
            'alg': 'HS256'
        }
        # 構造payload
        payload = {
            'user_id': request.user['user_id'],  # 自定義使用者ID
            'username': request.user['username'],  # 自定義使用者名稱
            'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5)  # 超時時間
        }
        token = jwt.encode(payload=payload, key=settings.SECRET_KEY, algorithm="HS256", headers=headers)
        return Response(token)

第四步 在統一返回格式處,新增過期欄位

class ResView:
    def finalize_response(self, request, response, *args, **kwargs):
        response = super().finalize_response(request, response, *args, **kwargs)
        if response.exception:
            return response
        response.data = {"code": 0, "data": response.data,"exp_time": request.user.get("exp_time")}
        return response

第五步 新增url

    path('api/jwt/update/', views.UpdateTokenView.as_view()),

第六步 前端部分 在 store中建立一個更新使用者資訊中token的函式

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const userInfoStore = defineStore('userInfo', () => {

    const userString = ref(localStorage.getItem("info"))
    const userDict = computed(() => userString.value ? JSON.parse(userString.value) : null)
    const userId = computed(() => userDict.value ? userDict.value.id : null)
    const userName = computed(() => userDict.value ? userDict.value.username : null)
    const userToken = computed(() => userDict.value ? userDict.value.token : null)


    function doLogin(info) {
      localStorage.setItem("info",JSON.stringify(info));
      userString.value = JSON.stringify(info)
    }


    function Logout(){
      localStorage.clear()
    }

    function updateUserInfo(new_token) {
      const userInfoObject = JSON.parse(userString.value);
      userInfoObject.token = new_token;
      localStorage.setItem("info",JSON.stringify(userInfoObject));
      userString.value = JSON.stringify(userInfoObject)
  }

    return {userDict,userId,userName,userToken,doLogin,Logout,updateUserInfo }
})

第七步 判斷返回的資料中 過期時間欄位,如果即將過期,就再發起一次更新token的操作

    onMounted(function getdata(){
    elLoading.value = true
    _axios.get("/api/project/").then(
        (res) =>{
            console.log("res.data:",res.data.data)
            console.log("res.data.count:",res.data.data.count)
            console.log("res.data.results.len:",res.data.data.page_size)
            console.log("res.data.exp:",res.data.exp_time)
            if (res.data.exp_time > 0 && res.data.exp_time < 30 ) {
                console.log("需要去更新token")
                _axios.get("/api/jwt/update/").then(
                    (res) =>{
                        console.log(res.data.data)
                        let new_token = res.data.data
                        userdata.updateUserInfo(new_token)
                    }
                )
            }
            response.value = res.data.data.results
            elLoading.value = false
            // 返回資料總數和每頁條數
            page.value = {
                count:res.data.data.count,
                page_size:res.data.data.page_size
            }

        }
    ).catch((reson) => {
        console.log("reson:",reson)
    })
    })

相關文章