淺談jwt在python中的使用


  • jwt概述

    1. 什么是jwt?

      json web token

    2. jwt應用場景?

      1. 微信小程序
      2. 移動設備
      3. 前后端分離項目
    3. 認證方式

      1. 傳統認證

        用戶登錄成功后,服務端下發token,並保存在服務端(database/session/redis/file)中,當客戶端再訪問服務端需要攜帶token,服務端獲取客戶端傳來的token后再去服務端(database/session/redis/file)中獲取token進行時間和token校驗,如果一樣,則順利訪問,否則提示token不合法或者過期。
        
      2. jwt認證

        用戶登錄成功后,服務端下發token,此時服務端並不保存token,當客戶端再訪問服務端時,需要攜帶token,服務端獲取客戶端傳來的token后,對此token通過某些算法進行分析來確認token是否合法。
        

    jwt實現過程

    1. 組成部分

      1. 頭部(HEADER)

        {
          "alg": "HS256",
          "typ": "JWT"
        }
        
      2. 載荷(PAYLOAD)

        {
          "sub": "1234567890",
          "name": "John Doe",
          "exp": 1516239022
        }
        
      3. 簽名(VERIFY SIGNATURE)

        HMACSHA256(
          base64UrlEncode(header) + "." +
          base64UrlEncode(payload),
        	SALT
        )
        
    2. 如何組成

      1. 將頭部使用base64UrlEncode編碼 得到StringA
      2. 將載荷使用base64UrlEncode編碼 得到StringB
      3. 將第一步和第二步 使用.進行字符串拼接 得到StringA.StringB
      4. 設置鹽值(SALT)
      5. 將第三步的字符串和鹽值進行hash256加密(為了安全使用鹽)得到hash256('StringA.StringB',SALT)
      6. 將第3步得到的字符串和第五步得到的hash256加密后的字符串用.進行拼接
    3. 最終生成結構

      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
      
    • 輔助函數

      # 封裝 base64UrlEncode方法
      def base64UrlEncode(data):
        '''
        	@params : dict
        	@return : string
        '''
        # 1. 判斷參數是否為字典,如不是字典直接返回
        if type(data) is not dict:
          return json.dumps({"code":1001,"msg":"參數類型不合法"},ensure_ascii=False)
        # 2.將字典轉成json串
        json_str = json.dumps(data)
        # 3.將json串轉成字節
        bytes_str = json_str.encode('utf-8')
        # 4.base64編碼
        b64_bytes = base64.b64encode(bytes_str)
        # 5.將字節類型轉成字符串類型,並返回
        return b64_bytes.decode('utf-8')
      
      # 封裝sha256方法
      import hashlib
      def sha256hex(raw,salt):
        '''
        @params: raw 原始字符串
        @params: salt 隨機鹽值
        @return : string
        '''
        new_str = raw+salt
        sha256 = hashlib.sha256()
        sha256.update(new_str.encode())
        return sha256.hexdigest()
      
    • 生成token

      # 代碼塊(生成token)
      from utils.helper import base64UrlEncode,sha256hex
      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.conf import settings
      class CreateTokenView(APIView):
          def post(self,request):
            # jwt頭部
              header = {
                "alg": "HS256",
                "typ": "JWT"
              }
              # jwt載荷
              payload = {
                  "sub": "1234567890",
                  "name": "John Doe",
                  "exp": 1516239022
              }
              # 頭部base64編碼
              header_string = base64UrlEncode(header)
              # 載荷base64編碼
              payload_string = base64UrlEncode(payload)
              # 鹽值
              salt = settings.SECRET_KEY
      				# 生成簽名
              sign = sha256hex(header_string+'.'+payload_string,salt)
              # 構造token
              token = header_string+"."+payload_string+"."+sign
              # 返回
              return Response({
                  "code":20000,
                  "data":{
                      "token":token
                  }
              })
      
      # 返回結果
      {
          "code": 20000,
          "data": {
              "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvaG4gRG9lIiwgImV4cCI6IDE1MTYyMzkwMjJ9.c7364fb2a00fe6aa843fae23e179fe97dd820f26a47a769c621ff560945278c7"
          }
      }
      
    • 驗證token

      # 代碼塊(生成token)
      from utils.helper import base64UrlEncode,sha256hex
      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.conf import settings
      class CheckTokenView(APIView):
          def post(self,request):
              # 獲取http headers  token
              token = request.META.get("HTTP_TOKEN")
              # 將token分解三部分
              payload_b64_header = token.split('.')[0]
              payload_b64_payload = token.split('.')[1]
              payload_b64_sign = token.split('.')[2]
              # 將第二部分解析,獲取過期時間
              json_str = base64_decode(payload_b64_payload)
              exp = json.loads(json_str)
              # 判斷當前時間和過期時間
              if exp['exp'] < int(time.time()):
                  return Response({
                      "code":1003,
                      "msg":"token過期"
                  })
              # 從配置文件中讀取鹽值
              salt = settings.SECRET_KEY
              # 在有效期內,判斷簽名是否一致
              sign = sha256hex(payload_b64_header+'.'+payload_b64_payload,salt)
              if sign == payload_b64_sign:
                  return Response({
                      "code":1000,
                      "msg":"驗證成功"
                  })
              return Response({
                  "code":"1002",
                  "msg":"驗證失敗"
              })    
      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM