赞
踩
JWT,JSON Web Token,基于 RFC7519,用于跨域认证 ,便于服务器集群认证
服务器认证后,生成一个 JWT 返回客户端,之后客户端与服务器通信都要发回这个 JSON,用于身份认证
客户端收到服务器返回的 JWT,可以存在 Cookie 里,也可以存在 localStorage
客户端通信时,可以放在 Cookie 里,也可以放在 Headers 的 Authorization 里,后一种可以解决跨域问题
JWT 用 .
分隔,分别为:
{"alg": "HS256", "typ": "JWT"}
alg
:生成签名算法,默认为 HS256typ
:令牌类型,默认为 JWTexp
(Expiration Time):过期时间nbf
(Not Before Time):生效时间iss
(Issuer):签发人aud
(Audience):受众iat
(Issued At):签发时间sub
(Subject):主题jti
(JWT ID):编号推荐阅读:
pip install PyJWT
import jwt
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') # 编码
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256']) # 解码
print(encoded_jwt) # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U
print(decoded_jwt) # {'some': 'payload'}
多数 JWT 使用对称算法 HS256 生成
import jwt
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') # 编码
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256']) # 解码
print(encoded_jwt) # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U
print(decoded_jwt) # {'some': 'payload'}
RS256 是非对称加密算法
安装
pip install cryptography
代码
import jwt
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
private_key = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
public_key = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
encoded_jwt = jwt.encode({'some': 'payload'}, private_key, algorithm='RS256') # 编码
decoded_jwt = jwt.decode(encoded_jwt, public_key, algorithms=['RS256']) # 解码
print(encoded_jwt)
print(decoded_jwt) # {'some': 'payload'}
import jwt
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256',
headers={'kid': '230498151c214b788dd97f22b85410a5'}) # 编码
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256']) # 解码
print(encoded_jwt)
print(decoded_jwt) # {'some': 'payload'}
参数 options={'verify_signature': False}
不进行签名校验
import jwt
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') # 编码
decoded_jwt = jwt.decode(encoded_jwt, options={'verify_signature': False}) # 解码
print(encoded_jwt)
print(decoded_jwt) # {'some': 'payload'}
import jwt
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') # 编码
unverified_header = jwt.get_unverified_header(encoded_jwt) # 读取头部
print(unverified_header) # {'typ': 'JWT', 'alg': 'HS256'}
支持以下字段
exp
(Expiration Time):过期时间,可用 UTC 时间戳或 datetime
解析超时报错 jwt.ExpiredSignatureError
参数 options={'verify_exp': False}
不进行过期时间校验
import datetime
import jwt
timestamp = int(datetime.datetime(2022, 1, 1).timestamp()) # 2022-01-01的时间戳,类型为int
after_a_week = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=7) # 一周后,类型为datetime
# 超时报错
encoded_jwt = jwt.encode({'exp': timestamp}, 'secret', algorithm='HS256')
try:
jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
except jwt.ExpiredSignatureError as e:
print(e) # Signature has expired
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'], options={'verify_exp': False}) # 不进行过期时间校验
print(decoded_jwt) # {'exp': 1640966400}
# 正常解析
encoded_jwt = jwt.encode({'exp': after_a_week}, 'secret', algorithm='HS256')
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
print(decoded_jwt) # {'exp': 1663252132}
nbf
(Not Before Time):生效时间,可用 UTC 时间戳或 datetime
解析未生效报错 jwt.ExpiredSignatureError
参数 options={'verify_nbf': False}
不进行过期时间校验
import datetime
import jwt
timestamp = int(datetime.datetime(2022, 1, 1).timestamp()) # 2022-01-01的时间戳,类型为int
after_a_week = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=7) # 一周后,类型为datetime
# 未生效报错
encoded_jwt = jwt.encode({'nbf': after_a_week}, 'secret', algorithm='HS256')
try:
jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
except jwt.ImmatureSignatureError as e:
print(e) # The token is not yet valid (nbf)
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'], options={'verify_nbf': False}) # 不进行生效时间校验
print(decoded_jwt) # {'nbf': 1663252132}
# 正常解析
encoded_jwt = jwt.encode({'nbf': timestamp}, 'secret', algorithm='HS256')
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
print(decoded_jwt) # {'nbf': 1640966400}
iss
(Issuer):签发人
签发人不匹配报错 jwt.InvalidIssuerError
import jwt
payload = {'some': 'payload', 'iss': 'urn:foo'}
encoded_jwt = jwt.encode(payload, 'secret', algorithm='HS256')
# 未生效报错
try:
jwt.decode(encoded_jwt, 'secret', issuer='tli:foo', algorithms=['HS256'])
except jwt.InvalidIssuerError as e:
print(e) # Invalid issuer
# 正常解析
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
print(decoded_jwt) # {'some': 'payload', 'iss': 'urn:foo'}
aud
(Audience):受众
受众不匹配报错 jwt.InvalidAudienceError
import jwt
payload = {'some': 'payload', 'aud': ['urn:foo', 'urn:bar']}
encoded_jwt = jwt.encode(payload, 'secret', algorithm='HS256')
# 未生效报错
try:
jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
except jwt.InvalidAudienceError as e:
print(e) # Invalid audience
# 正常解析
decoded_jwt = jwt.decode(encoded_jwt, 'secret', audience='urn:foo', algorithms=['HS256'])
print(decoded_jwt) # {'some': 'payload', 'aud': ['urn:foo', 'urn:bar']}
iat
(Issued At):签发时间
签发时间非数字或 datetime 报错 jwt.InvalidIssuedAtError
import datetime
import jwt
now = int(datetime.datetime.now(tz=datetime.timezone.utc).timestamp())
payload = {'some': 'payload', 'iat': now}
encoded_jwt = jwt.encode(payload, 'secret', algorithm='HS256')
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
print(decoded_jwt) # {'some': 'payload', 'iat': 1662620247}
必填 exp
、iss
、sub
import datetime
import jwt
after_a_week = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=7) # 一周后,类型为datetime
payload = {'some': 'payload', 'exp': after_a_week, 'iss': 'urn:foo', 'sub': 'foo'}
encoded_jwt = jwt.encode(payload, 'secret', algorithm='HS256')
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'], options={'require': ['exp', 'iss', 'sub']})
print(decoded_jwt) # {'some': 'payload', 'exp': 1663225440, 'iss': 'urn:foo', 'sub': 'foo'}
JWKS,JSON Web Key Set,指多个 JWK 组合在一起
import jwt
from jwt import PyJWKClient
token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA'
kid = 'NEE1QURBOTM4MzI5RkFDNTYxOTU1MDg2ODgwQ0UzMTk1QjYyRkRFQw'
url = 'https://dev-87evx9ru.auth0.com/.well-known/jwks.json'
jwks_client = PyJWKClient(url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
data = jwt.decode(
token,
signing_key.key,
algorithms=['RS256'],
audience='https://expenses-api',
options={'verify_exp': False},
)
print(data)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。