Esb*_*rdt 10 python decode public-key-encryption jwt azure-active-directory
当我从 Azure AD 使用 Python 收到 JWK 时,我想对其进行验证和解码。但是,我不断收到错误“签名验证失败”。
我有以下设置:
使用 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'])
Run Code Online (Sandbox Code Playgroud)
如果我将令牌放入https://jwt.io/这样的网站,一切看起来都很好。接下来,我需要来自 Azure 的公钥来验证令牌。
import requests
response = requests.get("https://login.microsoftonline.com/common/discovery/keys")
keys = response.json()['keys']
Run Code Online (Sandbox Code Playgroud)
为了将公钥与令牌相匹配,我在令牌标头中使用“kid”。我还知道使用哪种算法进行加密。
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
Run Code Online (Sandbox Code Playgroud)
现在我有来自 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
)
Run Code Online (Sandbox Code Playgroud)
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'
Run Code Online (Sandbox Code Playgroud)
我需要做的最后一件事是使用公钥验证令牌。
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"
)
Run Code Online (Sandbox Code Playgroud)
我得到的结果是:
jwt.exceptions.InvalidSignatureError: Signature verification failed
Run Code Online (Sandbox Code Playgroud)
我还尝试遵循这个流行指南:How to verify JWT id_token generated by MS Azure AD? 将 x5c 放入证书前缀和后缀中只会生成无效格式的错误。
大家能看出有什么明显的错误吗?我的主要猜测是受众或发行者有问题,但我无法确定问题是什么,而且微软的文档一如既往地糟糕。另外,Azure中的应用程序注册中有一个密钥,但它似乎也不起作用。
所以事实证明我的验证码是正确的,但我试图验证错误的令牌。创建轻微修改后,我现在收到一个 id_token,可以对其进行解码和验证。
至少有 2 个选项可用于解码 Microsoft Azure AD ID 令牌:
jwt
OP 提供的代码给了我例外InvalidIssuerError
。即使将issuer
参数替换为https://login.microsoftonline.com/{your-tenant-id}
对我来说也不起作用。然而,忽略这个参数让我能够解码 ID 令牌。这是完整的代码:
# Get the public keys from Microsoft
import requests
response = requests.get("https://login.microsoftonline.com/common/discovery/keys")
keys = response.json()['keys']
# Format keys as 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
)
# Get algorithm from token header
alg = jwt.get_unverified_header(your-id-token)['alg']
# Decode token
jwt.decode(
your-id-token,
key=rsa_pem_key_bytes,
algorithms=[alg],
verify=True,
audience=[your-client-id],
options={"verify_signature": True}
)
Run Code Online (Sandbox Code Playgroud)
msal
'sdecode_id_token
微软的包msal
提供了一个解码 id token 的函数。代码简单地变成:
from msal.oauth2cli.oidc import decode_id_token
decode_id_token(id_token=your-token-id, client_id=your-client-id)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6700 次 |
最近记录: |