安装
pip install pyjwt
加密依赖关系(可选)
如果您计划使用某些数字签名算法(如RSA或ECDSA)对令牌进行编码或解码,则需要安装 加密库。
pip install pyjwt[crypto]
pyjwt[crypto]在使用项目的需求文件中建议使用该PyJWT格式,因为单独的cryptography需求可能会在以后被误认为未使用的需求并被删除。
遗产依赖
某些环境,尤其是Google App Engine,不允许安装需要编译C扩展的Python包,因此无法安装cryptography。如果可以安装cryptography,则应忽略此部分。
如果要将应用程序部署到其中一个环境,则可能需要使用数字签名算法的传统实现:
pip install pycrypto ecdsa
一旦安装pycrypto和ecdcsa,你可以使用传统的jwt.register_algorithm()。以下示例代码显示了如何配置PyJWT以使用带有SHA256签名的RSA和带有SHA256签名的EC的旧版实现。
import jwt
from jwt.contrib.algorithms.pycrypto import RSAAlgorithm
from jwt.contrib.algorithms.py_ecdsa import ECAlgorithm
jwt.unregister_algorithm('RS256')
jwt.unregister_algorithm('ES256')
jwt.register_algorithm('RS256', RSAAlgorithm(RSAAlgorithm.SHA256))
jwt.register_algorithm('ES256', ECAlgorithm(ECAlgorithm.SHA256))
案例
- 使用HS256编码和解码令牌
>>import jwt
>>key = 'secret'
>>encoded = jwt.encode({'some': 'payload'}, key, algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
>>decoded = jwt.decode(encoded, key, algorithms='HS256')
{'some': 'payload'}
- 使用RS256(RSA)编码和解码令牌
>>import jwt
>>private_key = b'-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBS...'
>>public_key = b'-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEAC...'
>>encoded = jwt.encode({'some': 'payload'}, private_key, algorithm='RS256')
'eyJhbGciOiJIU...'
>>decoded = jwt.decode(encoded, public_key, algorithms='RS256')
{'some': 'payload'}
- 指定其他标题
>>jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256', headers={'kid': '230498151c214b788dd97f22b85410a5'})
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJzb21lIjoicGF5bG9hZCJ9.DogbDGmMHgA_bU05TAB-R6geQ2nMU2BRM-LnYEtefwg'
在没有验证的情况下读取声明集
如果您希望在不执行签名验证或任何已注册的声明名称的情况下阅读JWT的声明集,则可以将verify 参数设置为False。
注意:除非您清楚地了解自己在做什么,否则使用此功能通常是不明智的。如果没有数字签名信息,则无法信任声明集的完整性或真实性。
>>jwt.decode(encoded, verify=False)
{u'some': u'payload'}
无需验证即可读取标题
某些API要求您无需验证即可读取JWT标头。例如,在令牌发行者使用多个密钥并且您无法预先知道发行者的公钥或共享秘密中的哪一个用于验证的情况下,发行者可以在头部中包括密钥的标识符。
>>jwt.get_unverified_header(encoded)
{u'alg': u'RS256', u'typ': u'JWT', u'kid': u'key-id-12345...'}
注册要求的名字
JWT规范定义了一些注册的声明名称,并定义了它们的使用方式。PyJWT支持这些注册的声明名称:
- “exp” (Expiration Time) Claim
- “nbf” (Not Before Time) Claim
- “iss” (Issuer) Claim
- “aud” (Audience) Claim
- “iat” (Issued At) Claim
到期时间要求(exp)
“exp”(到期时间)声明标识JWT不得接受处理的时间或之后的到期时间。处理“exp”索赔要求当前日期/时间必须在“exp”索赔中列出的到期日期/时间之前。实施者可以提供一些小的余地,通常不超过几分钟,以解决时钟偏差。它的值必须是包含NumericDate值的数字。使用此声明是可选的。
您可以将到期时间作为UTC UNIX时间戳(int)或datetime传递,该时间将转换为int。例如:
jwt.encode({'exp': 1371720939}, 'secret')
jwt.encode({'exp': datetime.utcnow()}, 'secret')
如果到期时间是过去的,则在jwt.decode()中自动验证到期时间并引发 jwt.ExpiredSignatureError:
try:
jwt.decode('JWT_STRING', 'secret', algorithms=['HS256'])
except jwt.ExpiredSignatureError:
# Signature has expired
到期时间将与当前UTC时间进行比较(由 timegm(datetime.utcnow()。utctimetuple())),因此请务必在编码中使用UTC时间戳或日期时间。
您可以使用options参数中的verify_exp参数关闭到期时间验证。
PyJWT还支持到期时间定义的余地部分,这意味着您可以验证过去但不是很远的过期时间。例如,如果您有一个JWT有效负载,其过期时间设置为创建后30秒,但您知道有时您将在30秒后处理它,您可以设置10秒的余地以获得一些余量:
jwt_payload = jwt.encode({
'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30)
}, 'secret')
time.sleep(32)
# JWT payload is now expired
# But with some leeway, it will still validate
jwt.decode(jwt_payload, 'secret', leeway=10, algorithms=['HS256'])
可以使用datetime.timedelta实例,而不是将余地指定为秒数。上例中的最后一行相当于:
jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10), algorithms=['HS256'])
不在时间要求之前(nbf)
“nbf”(不在之前的)声明标识了JWT不得被接受进行处理的时间。处理“nbf”索赔要求当前日期/时间必须等于或等于“nbf”索赔中列出的不在日期/时间之前。实施者可以提供一些小的余地,通常不超过几分钟,以解决时钟偏差。它的值必须是包含NumericDate值的数字。使用此声明是可选的。
该NBF要求的工作方式与同样EXP要求之上。
jwt.encode({'nbf': 1371720939}, 'secret')
jwt.encode({'nbf': datetime.utcnow()}, 'secret')
发行人索赔(iss)
“iss”(发行人)索赔确定了发行JWT的委托人。该权利要求的处理通常是特定于应用的。“iss”值是包含StringOrURI值的区分大小写的字符串。使用此声明是可选的。
payload = {
'some': 'payload',
'iss': 'urn:foo'
}
token = jwt.encode(payload, 'secret')
decoded = jwt.decode(token, 'secret', issuer='urn:foo', algorithms=['HS256'])
如果发行者声明不正确,将引发jwt.InvalidIssuerError。
受众声明(aud)
“aud”(观众)声明标识了JWT的目标收件人。每个打算处理JWT的校验都必须在受众索赔中标明自己的价值。如果处理索赔的委托人在存在此索赔时未在“aud”索赔中标识其自身,那么JWT必须被拒绝。在一般情况下,“aud”值是一个区分大小写的字符串数组,每个字符串包含一个StringOrURI值。在JWT有一个受众的特殊情况下,“aud”值可以是包含StringOrURI值的单个区分大小写的字符串。对受众价值的解释通常是针对具体应用的。使用此声明是可选的。
payload = {
'some': 'payload',
'aud': 'urn:foo'
}
token = jwt.encode(payload, 'secret')
decoded = jwt.decode(token, 'secret', audience='urn:foo', algorithms=['HS256'])
生成时间(iat)
iat(发布于)声明确定了JWT发布的时间。该声明可用于确定JWT的年龄。它的值必须是包含NumericDate值的数字。使用此声明是可选的。
如果iat声明不是数字,则会引发jwt.InvalidIssuedAtError异常。
jwt.encode({'iat': 1371720939}, 'secret')
jwt.encode({'iat': datetime.utcnow()}, 'secret')