【发布时间】:2022-04-14 09:51:20
【问题描述】:
问题
当我在 Python 中收到来自 Azure AD 的 JWK 时,我想对其进行验证和解码。但是,我不断收到错误“签名验证失败”。
我的设置
我有以下设置:
- Azure 设置
在 Azure 中,我使用“仅限个人 Microsoft 帐户”设置创建了一个应用注册。 - Python 设置
在 Python 中,我使用 MSAL 包来接收令牌。我使用 Azure 的公钥来验证令牌。
代码
使用来自 Azure 门户的凭据,我设置了一个用于获取令牌的客户端。
import msal
ad_auth_client = msal.ConfidentialClientApplication(
client_id = client_id,
client_credential = client_secret,
authority = "https://login.microsoftonline.com/consumers"
)
my_token = ad_auth_client.acquire_token_for_client(scopes=['https://graph.microsoft.com/.default'])
如果我将令牌扔到像 https://jwt.io/ 这样的网站,一切看起来都很好。接下来我需要 Azure 的公钥来验证令牌。
import requests
response = requests.get("https://login.microsoftonline.com/common/discovery/keys")
keys = response.json()['keys']
为了将公钥与令牌匹配,我在令牌标头中使用了“孩子”。我还得到了用于加密的算法。
import jwt
token_headers = jwt.get_unverified_header(my_token['access_token'])
token_alg = token_headers['alg']
token_kid = token_headers['kid']
public_key = None
for key in keys:
if key['kid'] == token_kid:
public_key = key
现在我从 Azure 获得了正确的公钥来验证我的令牌,但问题是它是 JWT 密钥。在我可以使用它进行解码之前,我需要将其转换为 RSA PEM 密钥。
from cryptography.hazmat.primitives import serialization
rsa_pem_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(public_key))
rsa_pem_key_bytes = rsa_pem_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
这是 Azure 公钥的样子:
b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyr3v1uETrFfT17zvOiy0\n1w8nO+1t67cmiZLZxq2ISDdte9dw+IxCR7lPV2wezczIRgcWmYgFnsk2j6m10H4t\nKzcqZM0JJ/NigY29pFimxlL7/qXMB1PorFJdlAKvp5SgjSTwLrXjkr1AqWwbpzG2\nyZUNN3GE8GvmTeo4yweQbNCd+yO/Zpozx0J34wHBEMuaw+ZfCUk7mdKKsg+EcE4Z\nv0Xgl9wP2MpKPx0V8gLazxe6UQ9ShzNuruSOncpLYJN/oQ4aKf5ptOp1rsfDY2IK\n9frtmRTKOdQ+MEmSdjGL/88IQcvCs7jqVz53XKoXRlXB8tMIGOcg+ICer6yxe2it\nIQIDAQAB\n-----END PUBLIC KEY-----\n'
我需要做的最后一件事是使用公钥验证令牌。
decoded_token = jwt.decode(
my_token['access_token'],
key=rsa_pem_key_bytes,
verify=True,
algorithms=[token_alg],
audience=[client_id],
issuer="https://login.microsoftonline.com/consumers"
)
我得到的结果是:
jwt.exceptions.InvalidSignatureError: Signature verification failed
我也试过了
我也尝试遵循这个受欢迎的指南:How to verify JWT id_token produced by MS Azure AD? 将 x5c 放入证书前后缀只会产生格式无效的错误。
下一步是什么?
你们能看到任何明显的错误吗?我的主要猜测是 audience 或 issuer 有问题,但我无法确定是什么问题,而且 Microsoft 的文档一如既往的糟糕。此外,在 Azure 中的应用注册中有一个密钥,但它似乎也不起作用。
更新
结果证明我的验证码是正确的,但我试图验证错误的令牌。创建轻微修改后,我现在收到一个 id_token,可以对其进行解码和验证。
【问题讨论】:
-
猜测是观众或发行人有问题 - 错误的观众会导致`jwt.InvalidAudienceError`。但是观众参数是可选的,所以删除它进行测试,看看会发生什么。
-
你知道 issuer 是否也是可选的吗?如果我只输入密钥、秘密和算法,我会得到:[_OpenSSLErrorWithText(code=151584876, lib=9, reason=108, reason_text=b'error:0909006C:PEMroutines:get_name:no start line')]
-
这是 PyJWT,对吧?!那么是的,发行人也是可选的。 pyjwt.readthedocs.io/en/stable/usage.html#issuer-claim-iss。该错误似乎与密钥无关。试试看here
-
是的,它是 PyJWT
标签: python azure-active-directory jwt decode public-key-encryption