Python JWT 库 PyJWT 使用 HS256 签名时遇到问题 - 使用 SHA-256 哈希算法的 HMAC
Posted
技术标签:
【中文标题】Python JWT 库 PyJWT 使用 HS256 签名时遇到问题 - 使用 SHA-256 哈希算法的 HMAC【英文标题】:Python JWT library PyJWT trouble signing with HS256 - HMAC using SHA-256 hash algorithm 【发布时间】:2018-01-10 05:53:36 【问题描述】:尝试使用 PyJWT
库生成 JWT 令牌。
当我使用以下程序生成 JWT 令牌时 - 令牌不起作用。
但是,当我使用具有相同详细信息的网站 https://jwt.io/ 时 - 令牌有效。有什么我想念的吗。
我需要 python 正确生成令牌,以便我可以自动化一些需要此令牌的 API。
Python 程序:
import jwt
import base64
code = jwt.encode('sub':'String','nbf':'1501594247',
'exp':'1501767047', 'iss': 'string', 'aud': 'String',
base64.b64encode('secret'), algorithm='HS256')
print code
例子:
code = jwt.encode('sub':'AccountNUmber.QTVR','nbf':'1501594247','exp':'1501860089', 'iss': 'client_id', 'aud': 'https://login.google.com/oauth',
base64.b64encode('secret'), algorithm='HS256')
结果:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjbGllbnRfaWQiLCJhdWQiOiJodHRwczovL2xvZ2luLmdvb2dsZS5jb20vb2F1dGgiLCJzdWIiOiJBY2NvdW50TlVtYmVyLlFUVlIiLCJleHAiOiIxNTAxODYwMDg5IiwibmJmIjoiMTUwMTU5NDI0NyJ9.dRUUQYJ-RmxgoExwPyrvHPzX9SsxcpX1rOWlhisxNsg P>
https://jwt.io/生成的令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjbGllbnRfaWQiLCJhdWQiOiJodHRwczovL2xvZ2luLmdvb2dsZS5jb20vb2F1dGgiLCJzdWIiOiJBY2NvdW50TlVtYmVyLlFUVlIiLCJleHAiOiIxNTAxODYwMDg5IiwibmJmIjoiMTUwMTU5NDI0NyJ9.INp-ZnnL8Uj7MIwLYmpZtGyTyZG-oqZRNW8iZ145jVs P>
https://jwt.io/ 生成的令牌在我调用端点时有效。我得到一个状态码 200(成功)。
但是,当我使用从我的程序生成的令牌时,它会给出“无效令牌” - 400(错误请求)。
【问题讨论】:
“不起作用”到底是什么意思?你得到什么样的错误?你能请。将生成的令牌添加到您的问题中 jps 感谢您抽出宝贵时间回复。添加了一个示例并回答了上面的问题“不起作用”。让我知道我是否足够清楚。如果没有将尝试解释更多。 我想我知道它是如何工作的。仍然让我感到困惑的是,您上面的 jwt.io 生成的令牌有效。如果我的回答对你有用,请告诉我。 【参考方案1】:文档有错误,我查看了这个库的源代码
class PyJWT(PyJWS):
header_type = 'JWT'
@staticmethod
def _get_default_options():
# type: () -> Dict[str, bool]
return
'verify_signature': True,
'verify_exp': True,
'verify_nbf': True,
'verify_iat': True,
'verify_aud': True,
'verify_iss': True,
'require_exp': False,
'require_iat': False,
'require_nbf': False
def encode(self,
payload, # type: Union[Dict, bytes]
key, # type: str
algorithm='HS256', # type: str
headers=None, # type: Optional[Dict]
json_encoder=None # type: Optional[Callable]
):
# Check that we get a mapping
if not isinstance(payload, Mapping):
raise TypeError('Expecting a mapping object, as JWT only supports '
'JSON objects as payloads.')
# Payload
for time_claim in ['exp', 'iat', 'nbf']:
# Convert datetime to a intDate value in known time-format claims
if isinstance(payload.get(time_claim), datetime):
payload[time_claim] = timegm(payload[time_claim].utctimetuple()) # type: ignore
json_payload = json.dumps(
payload,
separators=(',', ':'),
cls=json_encoder
).encode('utf-8')
return super(PyJWT, self).encode(
json_payload, key, algorithm, headers, json_encoder
)
所以解决办法就是
from jwt.api_jwt import PyJWT
payload =
'id': 5,
'email': 'ASDASDA'
key = 'secret'
jwt_Obj=PyJWT()
jwt_token = jwt_Obj.encode( payload=payload,key= key )
decode_token=jwt_Obj.decode(jwt_token,key=key)
print (jwt_token)
print(decode_token)
输出应该或(必须)是 b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6IkFTREFTREEiLCJpZCI6NX0.-Woz4Crgi5KZj_D99eGaKxY4VxosY7r_e7HTD9JaDqE'
'email': 'ASDASDA', 'id': 5
【讨论】:
【参考方案2】:这里的错误是你的python语句中的base64.b64encode
。
在将秘密传递给jwt.encode
之前,您不应该对其进行编码。我认为 jwt.io 调试器在这方面有点误导:
这里的想法是,您有一个以 base64 编码格式存储的秘密,当您告诉 jwt.io 调试器它已编码时,它会解码您的秘密。
您可以在idle
中轻松查看:
>>> base64.b64encode('secret')
'c2VjcmV0'
如果您将编码后的密码粘贴到 jwt.io 上的 secret 字段并选中如上图所示的复选框,您将获得以下令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjbGllbnRfaWQiLCJhdWQiOiJodHRwczovL2xvZ2luLmdvb2dsZS5jb20vb2F1dGgiLCJzdWIiOiJBY2NvdW50TlVtYmVyLlFUVlIiLCJleHAiOiIxNTAxODYwMDg5IiwibmJmIjoiMTUwMTU5NDI0NyJ9.Nk6oCKBlT9lh4rtJZzF8JuyEsiH_HBaa3UhUx3DbWeI P>
这与以下 python 程序的输出相同:
a) 当您直接提供秘密而不是编码时:
code = jwt.encode('sub':'AccountNUmber.QTVR','nbf':'1501594247','exp':'1501860089', 'iss': 'client_id', 'aud': 'https://login.google.com/oauth',
'secret', algorithm='HS256')
b) 当您提供编码的秘密时:
code = jwt.encode('sub':'AccountNUmber.QTVR','nbf':'1501594247','exp':'1501860089', 'iss': 'client_id', 'aud': 'https://login.google.com/oauth',
base64.b64decode('c2VjcmV0'), algorithm='HS256')
这应该可行。
【讨论】:
jps,感谢您的回复。但是它仍然没有破解它。端点需要密码的 Base64 编码版本。所以你的方法1:直接秘密2.解码'秘密'的编码版本。两者都不起作用..你知道jet.encode是否对'secret'进行任何编码 如上所示,jwt.encode 不对密钥进行编码或解码。如果您提供如 a) 中的纯文本密码,则当您将纯文本密码粘贴到 jwt.io 时,您将获得与 jwt.io 相同的结果。如果你提供一个编码的秘密,你必须在将它传递给 jwt.encode 之前对其进行解码,这与 jwt.io 上的结果相同。我猜(我不知道你的端点)错误在端点端。关于处理编码或未编码的秘密可能存在类似的问题。请。仔细阅读我的回答,并在您的问题中提供更多信息。 你解决了吗?在我投入一些时间提供帮助后获得更新是公平的。以上是关于Python JWT 库 PyJWT 使用 HS256 签名时遇到问题 - 使用 SHA-256 哈希算法的 HMAC的主要内容,如果未能解决你的问题,请参考以下文章
在python中使用PyJWT解码jwt令牌给出错误算法不支持
如何使用带有公共 PEM 证书的 python PyJWT 验证 JWT?
使用 PyJWT 在 Python 中解码 Firebase JWT