使用Python的SqlManagementClient和MSAL登录时,程序化添加Azure SQL防火墙规则失败,提示'SqlManagementClient'对象无'firewall_rules'属性
使用Python的SqlManagementClient和MSAL登录时,程序化添加Azure SQL防火墙规则失败,提示'SqlManagementClient'对象无'firewall_rules'属性
问题分析
你遇到的这个错误本质上有两个核心原因:
- SDK版本迭代导致API结构变更:新版
azure-mgmt-sql(v4.0.0+)中,直接属于SqlManagementClient的firewall_rules属性已被移除,操作入口发生了变化; - 权限范围不匹配:你当前获取的令牌仅拥有数据库访问权限,但管理SQL服务器防火墙需要的是Azure资源管理器(ARM)的操作权限,两者的权限范围完全不同。
解决方案
我们需要从API调用路径和权限范围两个维度修正代码:
1. 修正防火墙规则的API调用路径
将原来的sql_client.firewall_rules替换为新版SDK的正确入口sql_client.server_firewall_rules。
2. 调整令牌的权限范围
获取交互式令牌时,使用ARM API的专属权限范围https://management.azure.com/.default,同时确保你的账号拥有SQL Server Contributor或更高权限的角色(你提到Azure Data Studio可正常使用,权限层面应该已满足)。
完整修正后的代码示例
from msal import PublicClientApplication from azure.identity import DefaultAzureCredential from azure.mgmt.sql import SqlManagementClient import pyodbc import requests # 替换为你的Azure资源配置信息 tenant_id = "your-tenant-id" client_id = "your-client-id" subscription_id = "your-subscription-id" resource_group_name = "your-resource-group" sql_server_name = "your-sql-server-name" firewall_rule_name = "Notebook-Temp-IP-Rule" # 自定义防火墙规则名称 server = f"{sql_server_name}.database.windows.net" database = "your-database-name" def add_firewall_rule(public_ip): credential = DefaultAzureCredential() sql_client = SqlManagementClient(credential, subscription_id) # 关键修正:使用新版SDK的server_firewall_rules入口 firewall_rule = sql_client.server_firewall_rules.create_or_update( resource_group_name=resource_group_name, server_name=sql_server_name, firewall_rule_name=firewall_rule_name, parameters={ "start_ip_address": public_ip, "end_ip_address": public_ip, } ) print(f"防火墙规则已创建/更新: {firewall_rule.name}") return firewall_rule # 获取ARM权限的令牌(用于管理SQL服务器资源) app = PublicClientApplication(client_id, authority=f"https://login.microsoftonline.com/{tenant_id}") result = app.acquire_token_interactive(scopes=["https://management.azure.com/.default"]) # 验证令牌获取是否成功 if "access_token" not in result: raise Exception(f"令牌获取失败: {result.get('error_description')}") # 获取当前机器的公网IP public_ip = requests.get("https://api.ipify.org").text print(f"当前公网IP: {public_ip}") # 添加防火墙规则 firewall_rule = add_firewall_rule(public_ip) # 单独获取数据库访问令牌 db_credential = DefaultAzureCredential() db_token = db_credential.get_token("https://database.windows.net/.default").token # 建立数据库连接 conn = pyodbc.connect( f"DRIVER={{ODBC Driver 18 for SQL Server}};" f"SERVER={server};" f"DATABASE={database};" f"Encrypt=yes;" f"TrustServerCertificate=no;" f"AccessToken={db_token};" ) print("数据库连接成功!") # 示例:执行简单查询验证连接 cursor = conn.cursor() cursor.execute("SELECT @@VERSION;") for row in cursor.fetchall(): print(row[0]) # 关闭资源 cursor.close() conn.close()
额外注意事项
- SDK版本验证:确保
azure-mgmt-sql为最新稳定版,可通过pip install --upgrade azure-mgmt-sql完成更新; - 防火墙规则命名建议:使用带有标识性的名称(如包含当前会话特征),避免与已有规则冲突;
- 权限隔离:建议分别获取管理资源和访问数据库的令牌,避免权限过大或范围不匹配的问题。
备注:内容来源于stack exchange,提问作者felixwcf
相关产品推荐
相关产品推荐

