本页介绍如何为用户和服务主体手动生成 Microsoft Entra ID 访问令牌,以便使用 Azure Databricks REST API 进行身份验证。 手动令牌生成是一种高级技术。
重要
Databricks 不建议手动创建Microsoft Entra ID 令牌。 它们将在一小时内过期,需要手动更换。 而是使用具有 统一身份验证 的工具或 SDK 自动处理令牌管理。
对大多数用例使用 Azure Databricks 托管服务主体 。 仅在需要访问 Azure 资源时才使用 Microsoft Entra ID 托管服务主体,因为这需要额外的 Microsoft Entra ID 权限。
何时使用手动令牌生成
仅在以下情况下使用手动令牌生成:
- 需要与无法使用 Azure CLI 或统一身份验证的系统集成
- 你需要显式地控制令牌的生命周期和刷新频率。
- 正在调试身份验证问题
对于所有其他用例,请使用自动处理令牌管理的推荐身份验证方法。
获取用户的令牌
使用 Azure CLI 或Microsoft身份验证库(MSAL)获取用户的Microsoft Entra ID 访问令牌。
Azure CLI 方法
获取用户帐户的 Azure 订阅 ID:
在 Azure Databricks 工作区中: 单击用户名 >Azure 门户>概述,找到 订阅 ID。
使用 Azure CLI: 运行以下命令(替换为工作区 URL):
az databricks workspace list --query "[?workspaceUrl==\`adb-0000000000000000.0.azuredatabricks.net\`].{id:id}" -o tsv # /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Databricks/workspaces/my-ws00000000-0000-0000-0000-000000000000之后的/subscriptions/是您的订阅 ID。如果出现租户错误,请登录正确的租户:
az login -t <tenant-id>请参阅 Azure 门户中的“获取订阅和租户 ID”。
登录到 Azure:
az login设置正确的订阅:
az account set -s <subscription-id>生成访问令牌:
az account get-access-token \ --resource 2ff814a6-3304-4ab8-85cb-cd0e6f879c1d \ --query "accessToken" \ -o tsv资源 ID
2ff814a6-3304-4ab8-85cb-cd0e6f879c1d是所有 Azure 环境中 Azure Databricks 的标准标识符。
MSAL 方法
使用 Microsoft身份验证库(MSAL) 以编程方式获取Microsoft Entra ID 访问令牌。 MSAL 支持两个流程:
- 授权代码流(交互式): 启动用于用户登录的浏览器。 启用双重身份验证或联合身份验证时,或者需要管理员同意时,请使用此功能。
- 用户名密码流(编程): 使用用户名和密码进行身份验证。 仅当具有以编程方式登录的权限时,才使用此功能。
在使用 MSAL 之前,必须在 Microsoft Entra ID 中注册应用程序。 请参阅 使用 Azure 门户注册应用。 注册时:
- 仅将支持的帐户类型设置为此组织目录中的帐户(单租户)。
- 设置 重定向 URI 为 公共客户端/本机(移动和桌面),值为
http://localhost。 - 记下应用的“概述”页中的应用程序(客户端)ID 和目录(租户)ID。
- 添加 AzureDatabricks API 权限:
- 转到 API 权限>添加权限。
- 搜索并选择 AzureDatabricks。
- 启用 user_impersonation 并单击“ 添加权限”。
- 单击“ 授予管理员许可 ”(需要管理员权限)。
授权代码流
安装 MSAL Python SDK:
pip install msal
将以下代码另存为 get-tokens.py:
from msal import PublicClientApplication
import sys
# Provide client ID and tenant ID as command-line arguments
client_id = sys.argv[1] if len(sys.argv) > 1 else '<client-id>'
tenant_id = sys.argv[2] if len(sys.argv) > 1 else '<tenant-id>'
scopes = ['2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default']
app = PublicClientApplication(
client_id=client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}"
)
result = app.acquire_token_interactive(scopes=scopes)
if 'error' in result:
print(f"Error: {result['error']}")
print(f"Description: {result['error_description']}")
else:
print(f"Access token:\n{result['access_token']}")
print(f"\nRefresh token:\n{result['refresh_token']}")
运行脚本:
python get-tokens.py <client-id> <tenant-id>
用户名-密码流
将以下代码另存为 get-tokens-user.py:
from msal import PublicClientApplication
import sys
client_id = sys.argv[1] if len(sys.argv) > 1 else '<client-id>'
tenant_id = sys.argv[2] if len(sys.argv) > 1 else '<tenant-id>'
username = sys.argv[3] if len(sys.argv) > 1 else '<username>'
password = sys.argv[4] if len(sys.argv) > 1 else '<password>'
scopes = ['2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default']
app = PublicClientApplication(
client_id=client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}"
)
result = app.acquire_token_by_username_password(
username=username,
password=password,
scopes=scopes
)
if 'error' in result:
print(f"Error: {result['error']}")
print(f"Description: {result['error_description']}")
else:
print(f"Access token:\n{result['access_token']}")
print(f"\nRefresh token:\n{result['refresh_token']}")
运行脚本:
python get-tokens-user.py <client-id> <tenant-id> <username> <password>
获取服务主体的令牌
服务主体使用 OAuth 2.0 客户端凭据流 ,并且可以具有与常规用户不同的访问控制。
创建服务主体
如果没有服务主体,请使用 Azure 门户或 Azure CLI 创建一个服务主体:
Azure 门户
- 登录到 Azure 门户。
- 如果需要,请使用 目录 + 订阅 切换到正确的租户。
- 搜索并选择 Microsoft Entra ID。
- 单击“ + 添加>应用注册”。
- 输入名称并选择“仅此组织目录中的帐户”(单租户)。
- 单击“注册”。
- 从 “概述 ”页复制这些值:
- 应用程序(客户端)ID
- 目录(租户)ID
- 转到 证书和机密>客户端机密>“新建客户端机密”。
- 添加说明,设置到期期限,然后单击“ 添加”。
- 复制并安全地存储客户端机密 值。
Azure CLI
有关完整说明,请参阅 使用 Azure CLI 创建 Azure 服务主体 。
生成令牌
使用 REST API 或 Azure CLI 生成令牌。 首先收集以下信息:
- 租户 ID:Microsoft Entra ID 中的目录(租户)ID
- 客户端 ID:Microsoft Entra ID 中的应用程序(客户端)ID
- 客户端密码:来自 Microsoft Entra ID 的客户端机密值
REST API 方法
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token \
-d 'client_id=<client-id>' \
-d 'grant_type=client_credentials' \
-d 'scope=2ff814a6-3304-4ab8-85cb-cd0e6f879c1d%2F.default' \
-d 'client_secret=<client-secret>'
访问令牌位于 access_token 响应的字段中。
Azure CLI 方法
获取 Azure 订阅 ID。 请参阅 获取用户的令牌。
使用服务主体登录:
az login \ --service-principal \ -t <tenant-id> \ -u <client-id> \ -p <client-secret>设置正确的订阅:
az account set -s <subscription-id>生成访问令牌:
az account get-access-token \ --resource 2ff814a6-3304-4ab8-85cb-cd0e6f879c1d \ --query "accessToken" \ -o tsv
将令牌与 Databricks API 配合使用
生成令牌后,将其与 Databricks REST API 一起使用。
工作区中的服务主体
如果您的服务主体已使用 服务主体 API 或 Databricks CLI 添加到工作区:
Databricks 命令行界面 (CLI)
databricks clusters list -p <profile-name-with-token>
curl
curl -X GET \
-H 'Authorization: Bearer <access-token>' \
https://<databricks-instance>/api/2.0/clusters/list
具有 Azure 角色的服务主体
如果服务主体在 Azure 中的工作区资源上具有 Contributor 或 Owner 角色,但尚不在 Azure Databricks 工作区中:
获取 Azure 资源管理器的管理令牌:
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' \ https://login.microsoftonline.com/<tenant-id>/oauth2/token \ -d 'client_id=<client-id>' \ -d 'grant_type=client_credentials' \ -d 'resource=https%3A%2F%2Fmanagement.core.windows.net%2F' \ -d 'client_secret=<client-secret>'使用两个令牌调用 Databricks API:
curl -X GET \ -H 'Authorization: Bearer <databricks-access-token>' \ -H 'X-Databricks-Azure-SP-Management-Token: <management-access-token>' \ -H 'X-Databricks-Azure-Workspace-Resource-Id: /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Databricks/workspaces/<workspace-name>' \ https://<databricks-instance>/api/2.0/clusters/list
首次身份验证后,服务主体将成为工作区管理员。
刷新令牌
如果使用访问令牌获取了刷新令牌,请使用它获取新令牌。 默认情况下,Microsoft Entra ID 访问令牌在 60-90 分钟后过期。
将以下代码另存为 refresh-tokens.py:
from msal import PublicClientApplication
import sys
client_id = sys.argv[1] if len(sys.argv) > 1 else '<client-id>'
tenant_id = sys.argv[2] if len(sys.argv) > 1 else '<tenant-id>'
refresh_token = sys.argv[3] if len(sys.argv) > 1 else '<refresh-token>'
scopes = ['2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default']
app = PublicClientApplication(
client_id=client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}"
)
result = app.acquire_token_by_refresh_token(
refresh_token=refresh_token,
scopes=scopes
)
if 'error' in result:
print(f"Error: {result['error']}")
print(f"Description: {result['error_description']}")
else:
print(f"\nNew access token:\n{result['access_token']}")
print(f"\nNew refresh token:\n{result['refresh_token']}")
运行脚本:
python refresh-tokens.py <client-id> <tenant-id> <refresh-token>
排查令牌问题
本部分介绍常见的令牌错误以及如何验证访问令牌。
未能使用用户名和密码获取令牌
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.
解决方案: 确保将 AzureDatabricks 资源添加到您的应用程序中。 使用授权代码流程(互动方式)授权许可。 同意后,可以使用用户名和密码认证流程。 请参阅 获取用户的令牌。
重定向 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:
2ff814a6-3304-4ab8-85cb-cd0e6f879c1d(Databricks 资源 ID) -
iss:
https://sts.windows.net/<tenant-id>/ - tid:工作区租户 ID
- nbf/exp:当前时间介于这些值之间
- unique_name:工作区中存在用户
使用 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])}")
使用签名验证进行解码:
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'
def get_public_key_for_token(kid):
response = requests.get('https://login.microsoftonline.com/common/.well-known/openid-configuration').json()
pubkeys = requests.get(response['jwks_uri']).json()['keys']
for key in pubkeys:
if key['kid'] == kid:
cert_str = PEMSTART + str(key['x5c'][0]) + PEMEND
cert_obj = load_pem_x509_certificate(bytes(cert_str, 'ascii'), default_backend())
return cert_obj.public_key()
def aad_access_token_decoder(access_token):
header = jwt.get_unverified_header(access_token)
public_key = get_public_key_for_token(header['kid'])
decoded = jwt.decode(access_token, key=public_key, algorithms='RS256',
audience='2ff814a6-3304-4ab8-85cb-cd0e6f879c1d')
for key in decoded.keys():
print(f"{key}: {str(decoded[key])}")