1,header
格式为字典-元数据格式如下
{‘alg’:‘HS256’, ‘typ’:‘JWT’}
#alg代表要使用的 算法
#typ表明该token的类别 - 此处必须为 大写的 JWT
1
2
3
该部分数据需要转成json串并用base64 加密
2,payload
格式为字典-此部分分为公有声明和私有声明
公共声明:JWT提供了内置关键字用于描述常见的问题
1
此部分均为可选项,用户根据自己需求 按需添加key,常见公共声明如下:
{‘exp’:xxx, # Expiration Time 此token的过期时间的时间戳
‘iss’:xxx,# (Issuer) Claim 指明此token的签发者
‘aud’:xxx, #(Audience) Claim 指明此token的
‘iat’:xxx, # (Issued At) Claim 指明此创建时间的时间戳
‘aud’:xxx, # (Audience) Claim 指明此token签发面向群体
}
1
2
3
4
5
6
私有声明:用户可根据自己业务需求,添加自定义的key,例如如下:
{‘username’: ‘guoxiaonao’}
1
公共声明和私有声明均在同一个字典中;转成json串并用base64加密
3,signature 签名
签名规则如下:
根据header中的alg确定 具体算法,以下用 HS256为例
HS256(自定义的key , base64后的header + b’.’ + base64后的payload)
解释:用自定义的key, 对base64后的header + b’.’ + base64后的payload进行hmac计算
2,jwt结果格式
base64(header) + b’.’ + base64(payload) + b’.’ + base64(sign)
最终结果如下: b’eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8iLCJpc3MiOiJnZ2cifQ.Zzg1u55DCBqPRGf9z3-NAn4kbA-MJN83SxyLFfc5mmM’
import base64
import json
import copy
import time
import hmac
class JWT:
def init(self):
pass
@staticmethod
def encode(payload,key,exp=300):
#init header
header = {'alg':'HS256','typ':'JWT'}
#将header 转成json串
header_json = json.dumps(header,sort_keys=True,separators=(',',':'))
#base64 - json串
header_bs = base64.urlsafe_b64encode(header_json.encode())
#init payload {'username':'guoxiaonao'}
payload = copy.deepcopy(payload)
payload['exp'] = time.time() + exp
payload_json = json.dumps(payload,sort_keys=True,separators=(',',':'))
payload_bs = base64.urlsafe_b64encode(payload_json.encode())
if isinstance(key,str):
key = key.encode()
#sign
hm = hmac.new(key,header_bs+ b'.' +payload_bs,digestmod='SHA256')
hm_bs = base64.urlsafe_b64encode(hm.digest())
return header_bs + b'.' + payload_bs + b'.' + hm_bs
if name == ‘main’:
res = JWT.encode({'username':'guoxiaonao',},'123456')
print(res)
结果:
b’eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjkzMTIyMjAuNjIyODg3LCJ1c2VybmFtZSI6Imd1b3hpYW9uYW8ifQ==.eqOdC9mh-puGT3Dx-KKCVtEWByplZeKVLgx0a_NRYsw=’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
3,校验jwt规则
1,解析header, 确认alg
2,签名校验 - 根据传过来的header和payload按 alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
3,获取payload自定义内容
4,若payload中含有exp,则校验过期时间
4,pyjwt
1,安装 pip3 install pyjwt
方法 参数说明 返回值
encode(payload, key, algorithm) payload: jwt三大组成中的payload,需要组成字典,按需添加公有声明和私有声明
例如: {‘username’: ‘guoxiaonao’, ‘exp’: 1562475112}
参数类型: dict token串
返回类型:bytes
key : 自定义的加密key
参数类型:str
algorithm: 需要使用的加密算法[HS256, RSA256等]
参数类型:str
decode(token,key,algorithm,) token: token串
参数类型: bytes/str payload明文
返回类型:dict
key : 自定义的加密key ,需要跟encode中的key保持一致
参数类型:str
algorithm: 同encode
issuer: 发布者,若encode payload中添加 ‘iss’ 字段,则可针对该字段校验
参数类型:str 若iss校验失败,则抛出jwt.InvalidIssuerError
audience:签发的受众群体,若encode payload中添加’aud’字段,则可针对该字段校验
参数类型:str 若aud校验失败,则抛出jwt.InvalidAudienceError
PS: 若encode得时候 payload中添加了exp字段; 则exp字段得值需为 当前时间戳+此token得有效期时间, 例如希望token 300秒后过期 {‘exp’: time.time() + 300}; 在执行decode时,若检查到exp字段,且token过期,则抛出jwt.ExpiredSignatureError
In [1]: import jwt
In [2]: jwt.encode({‘username’:‘guoxiaonao’},‘123456’,algorithm=‘HS256’)
Out[2]: b’eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8ifQ.kgWAwfADg3M79kr0rX3GW5zrkFdpUK2Uq_9qnQ9Ub4I’
In [3]: s = jwt.encode({‘username’:‘guoxiaonao’},‘123456’,algorithm=‘HS256’)
In [4]: jwt.decode(s,‘123456’,algorithm = ‘HS256’)
Out[4]: {‘username’: ‘guoxiaonao’}
这里面的’123456’是key,这个调包还是比较方便的~
1
2
3
4
5
6
7
8
9
10
11
我自己写的.py文件,可以切换time.sleep()来查看不同的结果,假如成功就会解析出信息,假如token过时,就会报错
import time
import jwt
def make_token(username, expire=3):
key = ‘123456’
now_t = time.time()
payload = {‘username’: username, ‘exp’: now_t + expire}
return jwt.encode(payload, key, algorithm=‘HS256’)
def func():
try:
b = make_token(‘123’)
# time.sleep(2)
time.sleep(4)
a = jwt.decode(b,‘123456’,algorithms=‘HS256’)
print(a)
except Exception as e:
print(e)
func()