能否本地模拟Azure用户分配托管身份以连接SQL Server开展调试?
可行实现方案(兼容.NET Core 3.1与.NET Framework 4.7.2)
核心思路
利用Azure.Identity库的DefaultAzureCredential类统一身份凭据获取逻辑,配合EF6的连接拦截器动态注入Azure AD访问令牌,本地通过切换身份配置实现和生产托管身份完全一致的权限模拟。
具体实现步骤
- 步骤1:安装依赖NuGet包
除已引入的ErikEJ.EntityFramework.SqlServer外,新增安装Azure.Identity包,选择兼容.NET Standard 2.0的版本即可同时适配两个目标框架。 - 步骤2:实现EF6连接拦截器
自定义拦截器在连接打开时注入访问令牌,本地调试时走模拟逻辑,生产环境保留原有托管身份连接字符串逻辑:using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Infrastructure; using Azure.Identity; using Microsoft.Data.SqlClient; using System.Configuration; // 自定义EF配置类,需和DbContext放在同一程序集 public class AdDbConfiguration : DbConfiguration { public AdDbConfiguration() { SetProviderServices(SqlProviderServices.ProviderInvariantName, SqlProviderServices.Instance); SetProviderFactory(SqlProviderServices.ProviderInvariantName, SqlClientFactory.Instance); AddInterceptor(new AdAuthInterceptor()); } } public class AdAuthInterceptor : IDbConnectionInterceptor { // 从配置读取当前要模拟的托管身份客户端ID private readonly string _targetMiClientId = ConfigurationManager.AppSettings["TargetManagedIdentityClientId"]; private readonly DefaultAzureCredential _credential; public AdAuthInterceptor() { _credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = _targetMiClientId }); } public void Opened(DbConnection connection, DbConnectionInterceptionContext context) { var sqlConn = connection as SqlConnection; // 判断为本地开发环境时手动注入令牌 bool isDev = ConfigurationManager.AppSettings["Environment"] == "Development" || Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development"; if (sqlConn != null && isDev) { var token = _credential.GetToken( new Azure.Core.TokenRequestContext(new[] { "https://database.windows.net/.default" }), default ); sqlConn.AccessToken = token.Token; } } // 其余IDbConnectionInterceptor接口方法直接空实现即可 public void Opening(DbConnection connection, DbConnectionInterceptionContext context) { } public void Closed(DbConnection connection, DbConnectionInterceptionContext context) { } public void Closing(DbConnection connection, DbConnectionInterceptionContext context) { } public void Disposed(DbConnection connection, DbConnectionInterceptionContext context) { } public void Disposing(DbConnection connection, DbConnectionInterceptionContext context) { } public void BeganTransaction(DbConnection connection, BeginTransactionInterceptionContext context) { } public void BeginningTransaction(DbConnection connection, BeginTransactionInterceptionContext context) { } public void EnlistedTransaction(DbConnection connection, EnlistTransactionInterceptionContext context) { } public void EnlistingTransaction(DbConnection connection, EnlistTransactionInterceptionContext context) { } } - 步骤3:本地多身份调试配置
要模拟不同托管身份访问不同schema的场景,只需修改配置文件中的TargetManagedIdentityClientId值,同时按以下两种方式之一配置身份凭据:- 方式1:本地安装Azure CLI,执行
az login登录拥有对应托管身份模拟权限的账号,调试时自动拉取登录账号的凭据获取令牌 - 方式2:配置对应托管身份的服务主体环境变量:
AZURE_CLIENT_ID、AZURE_TENANT_ID、AZURE_CLIENT_SECRET,DefaultAzureCredential会自动读取该配置以目标托管身份的身份获取令牌,权限表现和生产完全一致
- 方式1:本地安装Azure CLI,执行
注意事项
- 本地模拟使用的账号/服务主体需要和目标托管身份配置完全一致的SQL角色、schema访问权限,才能1:1复现生产环境的权限表现
- 生产环境无需修改原有连接字符串和逻辑,仍保留
Authentication=Active Directory Managed Identity;User Id=<clientId of managed identity>;配置即可正常运行
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

