# 使用者登入,返回給客戶端token(服務端不儲存),使用者帶著token,服務端拿到token再校驗; 1,提交使用者名稱和密碼給服務端,如果登陸成功,jwt會建立一個token,並返回; 第一段:header,內部包含 (演算法/token型別) { "typ": "JWT", # 宣告型別為jwt "alg": "HS256" # 宣告簽名演算法為SHA256 } # json轉化字串做base64url加密,可反解 第二段:payload,包含(標準中註冊的宣告、公共宣告、私有宣告(使用者資訊)) { # 私有聲名 “id”: “12”, “name”: “bajie″, “exp”: 60 # 超時時間 } # 公共宣告:公共的宣告可以新增任何的資訊,一般新增使用者的相關資訊或其他業務需要的必要資訊. """ 註冊的宣告 iss: jwt簽發者 sub: jwt所面向的使用者 aud: 接收jwt的一方 exp: jwt的過期時間,這個過期時間必須要大於簽發時間 nbf: 定義在什麼時間之前,該jwt都是不可用的. iat: jwt的簽發時間 jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。 """ # json轉化字串做base64url加密,可反解 第三段: 1,將第一段和第二段的密文拼接 2,HS256加密 + 加鹽 3,對HS256加密後的密文再用 base64url 加密 2,使用者訪問,需要攜帶token,後端進行校驗 1,獲取token 2,切割,對第二段解密,獲取payload資訊,檢測是否超時 3,把第一段和第二段的密文拼接,再次執行HS256加密 + 加鹽 得到 密文 4,密文 == token 匹配 (如果修改超時時間 則不通過)
安裝: pip install pyjwt import jwt import datetime from rest_framework.views import APIView from rest_framework.response import Response from jwt import exceptions from api import models class LoginAPIview(APIView): def get(self, request, *args, **kwargs): # 鹽 sail = "sadjmasklfn63a5s62dwa@ddas/352asdfa" """ 1,獲取token 2,切割,對第二段解密,獲取payload資訊,檢測是否超時 3,把第一段和第二段的密文拼接,再次執行HS256加密 + 加鹽 得到 密文 4,密文 == token 匹配 (如果修改超時時間 則不通過) """ token = request.query_params.get("token") verified_payload = None msg = '' try: # 反解出來的第二段資料 verified_payload = jwt.decode(token, sail, True) except exceptions.ExpiredSignatureError: # 超時 msg = "token失效" except jwt.DecodeError: msg = "token認證失敗" except jwt.InvalidTokenError: msg = "非法token" if not verified_payload: return Response({'code': '登入失敗', "error": msg}) # print(verified_payload["id"],verified_payload["username"]) return Response({"ok": "登陸成功"}) def post(self, request, *args, **kwargs): user = request.data.get('username') pswd = request.data.get('password') obj = models.UserInfo.objects.filter(username=user, password=pswd).first() if obj: # 鹽 sail = "sadjmasklfn63a5s62dwa@ddas/352asdfa" # 構造 第一段: header, 內部包含(演算法 / token型別) 預設 headers = { "typ": "JWT", # 宣告型別為jwt "alg": "HS256" # 宣告簽名演算法為SHA256 } # 第二段: payload, 包含(標準中註冊的宣告、公共宣告、私有宣告(使用者資訊)) payload = { # 私有聲名 'id': obj.id, 'username': obj.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=1) # 超時時間1分鐘 } res_token = jwt.encode(headers=headers, payload=payload, key=sail, algorithm='HS256').decode('utf-8') return Response({"msg": "登入成功", "token": res_token}) return Response("0")