【问题标题】:How to verify JWT produced by Azure Ad?如何验证 Azure Ad 生成的 JWT?
【发布时间】:2022-04-14 09:51:20
【问题描述】:

问题

当我在 Python 中收到来自 Azure AD 的 JWK 时,我想对其进行验证和解码。但是,我不断收到错误“签名验证失败”。

我的设置

我有以下设置:

  1. Azure 设置
    在 Azure 中,我使用“仅限个人 Microsoft 帐户”设置创建了一个应用注册。
  2. 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 放入证书前后缀只会产生格式无效的错误。

下一步是什么?

你们能看到任何明显的错误吗?我的主要猜测是 audienceissuer 有问题,但我无法确定是什么问题,而且 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


【解决方案1】:

您获得了范围https://graph.microsoft.com/.default 的令牌,这意味着访问令牌适用于 MS Graph API。 您不应该验证这一点,这是 API 的工作。 Graph API 也很特殊,它使用与其他 API 不同的签名方法。

【讨论】:

  • 所以我收到的令牌不应该被验证?我想使用 Azure AD 进行访问控制,这样只有属于某个 AD 组的用户才能访问我的应用程序。 MSAL 文档仅包含对 Graph API 的委派访问示例。所以我的想法是,如果只有属于某个 AD 组的用户才能获得令牌,并且我可以验证令牌,那么我就可以毕业访问。你还有什么建议吗? :)
  • 是的,我可以指点一下 :) 你能告诉我这是什么类型的应用程序吗?例如,这是一个 Web 应用程序吗?通常,应用程序将:验证用户身份,验证应用程序的 id 令牌/访问令牌,(可选)检查令牌中的用户角色,(可选)检查令牌中的应用权限,(可选)通过令牌或 MS Graph API 检查用户组.
  • 酷!因此,这适用于用 Python 编写的非常简单的烧瓶 Web 应用程序。我以前使用过 jwt 身份验证,其中每个端点都装饰有验证令牌的函数。现在我工作的组织希望我们使用相同的 AD 身份验证,所以我的想法是使用相同的方法。但是,我在验证来自 azure 的令牌时遇到问题。我不喜欢使用 Azure 指南中的会话,因为这不再是最佳实践。此外,在 Microsoft 文档中,他们没有关于如何验证其令牌的示例。
  • 听起来您的应用程序是一个后端 Web 应用程序,没有单页应用程序(React、Angular 等)前端。这些应用程序通常使用授权代码 OAuth 流来获取令牌。遗憾的是,我没有使用 Python,所以我真的不能说要使用哪些库..
  • 感谢您的意见,我会想办法的:)
猜你喜欢
  • 2017-08-25
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 2016-12-02
  • 2020-07-08
  • 2018-12-25
  • 2017-03-31
  • 2017-09-25
相关资源
最近更新 更多