You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Azure服务主体与MSAL从Databricks Python Notebook通过PySpark JDBC驱动连接MS SQL Server时的令牌(访问权限)错误解决方法咨询

Azure服务主体与MSAL从Databricks Python Notebook通过PySpark JDBC驱动连接MS SQL Server时的令牌(访问权限)错误解决方法咨询

嘿,我之前也碰到过一模一样的问题——用ADAL连接完全没问题,但切换到MSAL就各种令牌报错,折腾了好一阵才搞定。下面是我亲测有效的解决步骤和注意事项,应该能帮你顺利打通连接:

先确认基础权限配置

这一步很容易被忽略,但却是所有连接的前提:

  • 确保你的Azure服务主体(SPN)已经被添加为MS SQL Server的Azure AD登录用户,并且在目标数据库中创建了对应的用户,分配了所需的角色(比如db_datareader、db_datawriter)。
  • 给SPN分配Azure层面的权限:至少需要Azure SQL Database Contributor角色(或者更细粒度的权限,根据你的需求调整),确保它能访问目标SQL资源。
  • 检查SQL Server的防火墙规则:必须允许Databricks集群的出站IP访问(如果是无服务器集群,可以考虑添加Azure Databricks的服务标签)。

选择正确的依赖库

你提到的两个库不要同时使用,避免驱动版本冲突:

  • 优先选择com.microsoft.azure:spark-mssql-connector_2.12:1.1.0(或更新的稳定版本,比如1.2.0),这个连接器对MSAL的支持更原生,适配Databricks的环境也更好。
  • 直接在Databricks集群的“库”配置里添加这个Maven依赖即可,不需要额外安装databricks-jdbc驱动。

用MSAL正确获取访问令牌

这里关键是要拿到SQL Server认可的有效令牌,推荐用两种方式:

方式1:用MSAL Python库手动获取

先在集群里通过pip安装msal库(可以在Notebook里执行%pip install msal),然后用以下代码获取令牌:

import msal

# 从Databricks Secrets中读取敏感信息(千万不要硬编码!)
tenant_id = dbutils.secrets.get(scope="你的密钥范围名称", key="tenant-id")
client_id = dbutils.secrets.get(scope="你的密钥范围名称", key="spn-client-id")
client_secret = dbutils.secrets.get(scope="你的密钥范围名称", key="spn-client-secret")
sql_resource_url = "https://database.windows.net/"

# 初始化MSAL客户端应用
msal_app = msal.ConfidentialClientApplication(
    client_id=client_id,
    authority=f"https://login.microsoftonline.com/{tenant_id}",
    client_credential=client_secret
)

# 获取针对Azure SQL的令牌,注意scope必须是`https://database.windows.net/.default`
token_result = msal_app.acquire_token_for_client(scopes=[f"{sql_resource_url}.default"])

if "access_token" in token_result:
    access_token = token_result["access_token"]
else:
    raise Exception(f"令牌获取失败:{token_result.get('error_description', '未知错误')}")

方式2:用Databricks内置TokenLibrary(更安全)

如果你的Databricks工作区支持,可以用内置的TokenLibrary直接获取令牌,省去手动处理MSAL的步骤:

from databricks.sdk.core import TokenLibrary

tenant_id = dbutils.secrets.get(scope="你的密钥范围名称", key="tenant-id")
access_token = TokenLibrary.getAzureToken("https://database.windows.net/", tenant_id)

配置PySpark JDBC连接

拿到令牌后,就可以配置JDBC连接了,核心是把令牌传递给accessToken参数,而不是用传统的用户名密码:

用Spark SQL Connector的方式(推荐)

sql_server_name = "你的sql-server名称.database.windows.net"
database_name = "你的数据库名称"
jdbc_url = f"jdbc:sqlserver://{sql_server_name}:1433;databaseName={database_name};encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"

# 读取数据
df = spark.read \
    .format("com.microsoft.sqlserver.jdbc.spark") \
    .option("url", jdbc_url) \
    .option("dbtable", "你的架构名称.你的表名称") \
    .option("accessToken", access_token) \
    .load()

# 写入数据(如果需要)
df.write \
    .format("com.microsoft.sqlserver.jdbc.spark") \
    .option("url", jdbc_url) \
    .option("dbtable", "你的架构名称.目标表名称") \
    .option("accessToken", access_token) \
    .mode("append") \
    .save()

用原生JDBC驱动的方式

如果你更倾向于用原生JDBC驱动,也可以这么配置:

df = spark.read.format("jdbc") \
    .option("url", jdbc_url) \
    .option("dbtable", "你的架构名称.你的表名称") \
    .option("accessToken", access_token) \
    .option("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver") \
    .load()

常见的令牌错误坑点

  • Scope错误:一定要用https://database.windows.net/.default作为令牌请求的scope,用其他值会导致SQL Server拒绝令牌。
  • 依赖冲突:同时安装databricks-jdbc和mssql-connector会导致JDBC驱动版本冲突,令牌处理逻辑混乱,只保留其中一个即可。
  • 令牌过期:MSAL客户端令牌默认有效期是1小时,如果你的作业运行超过1小时,需要重新获取令牌,建议把令牌获取逻辑封装成函数,按需调用。
  • SPN权限缺失:除了SQL Server的权限,还要确保SPN没有被Azure AD的条件访问策略限制,比如MFA要求(服务主体不需要MFA,但如果策略强制所有主体都要MFA,可能会出问题)。

备注:内容来源于stack exchange,提问作者StephenDonaldHuffPhD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 08:09:37