JWT, token的設計和驗證

JWT (json web token)是一種http request主流加密方式,相比傳統的token,JWT的優勢在於無狀態傳播,不需要存儲到數據庫,就可以實現安全令牌驗證,缺點是一經簽發,exp失效前令牌都會一直有效,此認證狀態無法更改。

JWT無法被破解的關鍵,是在其第三部分簽名裏的哈希加密中的鹽值。

由於哈希加密是無法直接解密的,所以jwt實際上只是重複使用加密的過程進行驗證而已。

具體過程

一、頭部 (head)

包含了具體的算法,如HS256 HS512等,typ類型:JWT,通常寫法

二、負載(payload)

包含了關鍵信息,包含用戶名,過期日期,其他自定義鍵值等

三、簽名(sign)

將一二部分進行base64加密後的結果再進行哈希加鹽加密,處理後的最後字符串爲關鍵驗證信息。

注意:base64加密方式中原表的“/“,"+","="這三個字符,在進行JWT加密時通用的base64url加密,在加密過程中將其會替換成“-”,“_”,並去掉“=”。

 

 

具體加密過程:

將頭部字典變爲json格式(json.dumps),並將其分割符號變爲“,”與“:”,去掉空格緊湊分割

將頭部進行base64url加密,再去掉裏面的“=”,

 

將負載中的exp添加鍵值:即爲過期日期,格式爲int

將其同樣處理爲json格式,再進行base64url加密

 

將頭部和負載相連,中間用"."符號連接。

檢查鹽值,如果鹽裏面有字符串,將其encode爲二進制字節串

對連接好的頭部負載進行哈希加密,輸入鹽值,方法(hmac.new(鹽值,簽名,digestmod='SHA256'))

將處理好的sign再進行簽名化處理  (x.digest()方法)

爲其再次進行base64加密處理,得到最終的簽名令牌

 

最後,將頭部、負載、簽名再使用b“.”連接起來,就得到完全的JWT了,這就是其完整處理過程

 

 

 

代碼:

import copy
import hmac
import json
import base64
import time


class Jwt():
    def __init__(self):
        pass
    @staticmethod
    def encode(payload, key, exp=300):
        #create header
        header = {'alg':'HS256','typ':'JWT'}
        header_j = json.dumps(header, separators=(',',':'),sort_keys=True)

        header_bs = Jwt.b64encode(
            header_j.encode())
        payload = copy.deepcopy(payload)
        payload['exp'] = int(time.time()) + exp
        payload_j = json.dumps(payload, separators=(',',':'), sort_keys=True)

        payload_bs = Jwt.b64encode(payload_j.encode())

        to_sign_str = header_bs + b'.' + payload_bs

        if isinstance(key, str):
            key = key.encode()
        hmac_obj = hmac.new(key,to_sign_str,
                            digestmod='SHA256')
        sign = hmac_obj.digest()
        sign_bs = Jwt.b64encode(sign)
        return header_bs + b'.' + payload_bs + b'.' + sign_bs

    @staticmethod
    def b64encode(s):
        return base64.urlsafe_b64encode(s).replace(b'=',b'')

    @staticmethod
    def b64decode(s):
        mod = len(s) % 4
        s += b'='*(4-mod)
        return base64.urlsafe_b64decode(s)
    @staticmethod
    def decode(token,key):
        header_bs,payload_bs,sign = token.split(b'.')
        if isinstance(key, str):
            key = key.encode()
        hm = hmac.new(key, header_bs + b'.' + payload_bs,digestmod='SHA256')
        new_sign = Jwt.b64encode(hm.digest())
        if sign != new_sign:
            raise JwtSignError('Your token is not true')

        payload_j = Jwt.b64decode(payload_bs)
        print(type(payload_j))
        payload = json.loads(payload_j)
        exp = payload['exp']
        now = time.time()
        if now > exp:
            raise JwtSignError('Your token is valid')
        return payload
class JwtSignError(Exception):
    def __init__(self,error_msg):
        self.error = error_msg
    def __str__(self):
        return '<JwtError error %s>' %(self.error)

if __name__ == "__main__":
    res = Jwt.encode({'username':'lxxx'},'abcdef1234',1)
    print(Jwt.decode(res,'abcdef1234'))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章