最近要用 Falsk 开发一个大点的后端,为了安全考虑,弃用传统的Cookie验证。转用JWT。
其实 Falsk 有一个 Falsk-JWT 但是我觉得封装的太高,还是喜欢通用的 PyJWT 。
JWT官网
https://jwt.io/
安装
pip install PyJWT
项目文档(英文)
https://pyjwt.readthedocs.io/en/latest/
Demo
import jwt import datetime dic = { 'exp': datetime.datetime.now() + datetime.timedelta(days=1), # 过期时间 'iat': datetime.datetime.now(), # 开始时间 'iss': 'lianzong', # 签名 'data': { # 内容,一般存放该用户id和开始时间 'a': 1, 'b': 2, }, } s = jwt.encode(dic, 'secret', algorithm='HS256') # 加密生成字符串 print(s) s = jwt.decode(s, 'secret', issuer='lianzong', algorithms=['HS256']) # 解密,校验签名 print(s) print(type(s))
结果
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NDUzMDI5OTIsImlhdCI6MTU0NTIxNjU5MiwiaXNzIjoibGlhbnpvbmciLCJkYXRhIjp7ImEiOjEsImIiOjJ9fQ.pSq-XRcC-E7zeg3u0X6TsKdhhsCPh3tB40_YJNho8CY' {'exp': 1545302992, 'iat': 1545216592, 'iss': 'lianzong', 'data': {'a': 1, 'b': 2}} <class 'dict'>
解析
首先我们注意dic的结构
dic 有官方指定的key,程序在解密的时候会根据key的Value判断是否合法。这些key有
- “exp”: 过期时间
- “nbf”: 表示当前时间在nbf里的时间之前,则Token不被接受
- “iss”: token签发者
- “aud”: 接收者
- “iat”: 发行时间
我们一般设置 过期时间,发行时间,接收者。我们来分别解释这些key
exp
exp指过期时间,在生成token时,可以设置该token的有效时间,如果我们设置1天过期,1天后我们再解析此token会抛出
jwt.exceptions.ExpiredSignatureError: Signature has expired
nbf
nbf类似于token的 lat ,它指的是该token的生效时间,如果使用但是没到生效时间则抛出
jwt.exceptions.ImmatureSignatureError: The token is not yet valid (nbf)
iss
iss指的是该token的签发者,我们可以给他一个字符串。
注意,iss 在接收时如果不检验也没有问题,如果我们接收时需要检验但是又签名不一致,则会抛出
jwt.exceptions.InvalidIssuerError: Invalid issuer
aud
aud指定了接收者,接收者在接收时必须提供与token要求的一致的接收者(字符串),如果没写接收者或者接收者不一致会抛出
jwt.exceptions.InvalidAudienceError: Invalid audience
iat
iat指的是token的开始时间,如果当前时间在开始时间之前则抛出
jwt.exceptions.InvalidIssuedAtError: Issued At claim (iat) cannot be in the future.
注意
如果我们不需要验证所有信息直接生成token可以设置
jwt.decode(encoded, verify=False)
但是这样有什么用呢?
生成/解密参数
jwt.encode(payload, config.SECRET_KEY, algorithm='HS256')
上面代码的jwt.encode方法中传入了三个参数:第一个是payload,这是认证依据的主要信息,第二个是密钥,这里是读取配置文件中的SECRET_KEY配置变量,第三个是生成Token的算法。
一般我们使用HS256
第二个参数是生成token的密钥
我们需要在加密时指定
解密时也是第二个参数来指定解密密钥,这两个密钥必须相同