对 Microsoft Entra ID 访问令牌进行故障排除

本文介绍如何排查在获取 Microsoft Entra ID 访问令牌时可能遇到的错误,以及如何验证访问令牌。

无法使用用户名和密码获取令牌

错误消息

The user or administrator has not consented to use the application with ID <client-id>.
Send an interactive authorization request for this user and resource.

解决方案

  1. 如果 AzureDatabricks 资源未添加到你的应用程序,请要求管理员用户添加它。
  2. 使用交互式方法获取令牌。 该网页将指导你向应用程序授予权限。 或者,单击应用程序配置中描述的“授予权限”按钮。 授予权限后,可以使用编程方法获取令牌。

重定向 URI 不匹配

错误消息

The reply URL specified in the request does not match the reply URLs configured for the application: '<application-id>'

解决方案

检查请求中的重定向 URI 是否与应用程序中的重定向 URI 相匹配。

验证访问令牌

如果有 Microsoft Entra ID 访问令牌,可以验证它是否包含正确的信息(请参阅验证令牌)。

应该验证以下字段是否与记录匹配:

  • aud:Azure Databricks 资源 ID:
  • iss:应为
  • tid:应为工作区的租户(通过组织 ID 或工作区设备 ID 查找)
  • nbf/exp:当前时间应介于 nbf 之间
  • unique_name:应是 Databricks 工作区中的用户,除非该用户是工作区设备资源的贡献者

使用 OIDC 终结点中的公共证书验证令牌签名。

下面是显示令牌有效负载的代码片段。 必须先使用 安装 pip install pyjwt 库,然后再使用 pip install cryptography 安装加密库:

import jwt

def decode_token(token):
  algorithm = jwt.get_unverified_header(token)['alg']

  decoded = jwt.decode(
    token,
    algorithms = [algorithm],
    options = {"verify_signature": False}
  )

  for key in decoded.keys():
     print(f"{key}: {str(decoded[key])}")

如果要对令牌进行完全解码(包括签名验证),可以使用以下代码片段。 必须先使用 安装 pip install pyjwt 库,然后再使用 pip install cryptography 安装加密库。 此外,请确保在以下代码中替换 <databricks-resource-id>

import jwt
import requests
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend

PEMSTART = '-----BEGIN CERTIFICATE-----\n'
PEMEND = '\n-----END CERTIFICATE-----\n'

# Get the Microsoft Azure public key.
def get_public_key_for_token(kid):
  response = requests.get(
    'https://login.microsoftonline.com/common/.well-known/openid-configuration',
  ).json()

  jwt_uri = response['jwks_uri']
  response_keys = requests.get(jwt_uri).json()
  pubkeys = response_keys['keys']

  public_key = ''

  for key in pubkeys:
    # Find the key that matches the kid in the token's header.
      if key['kid'] == kid:
        # Construct the public key object.
        mspubkey = str(key['x5c'][0])
        cert_str = PEMSTART + mspubkey + PEMEND
        cert_obj = load_pem_x509_certificate(bytes(cert_str, 'ascii'), default_backend())
        public_key = cert_obj.public_key()

  return public_key

# Decode the given <ms-entra-id> token.
def aad_access_token_decoder(access_token):
  header = jwt.get_unverified_header(access_token)
  public_key = get_public_key_for_token(header['kid'])
  # The value of the databricks_resource_id is as defined previously,
  # for example, databricks_resource_id = "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d"
  decoded = jwt.decode(
    access_token,
    key = public_key,
    algorithms = 'RS256',
    audience = '<databricks-resource-id>')

  for key in decoded.keys():
    print(f"{key}: {str(decoded[key])}")

还可以通过在线 JWT 解码器查看已解码的令牌(如果它们不敏感)。 在线解码器的示例是 jwt.msjwt.io