ASP.NET Core 2.0+EF Core使用DI与Azure Key Vault时的脚手架问题
我太懂你这种纠结了——用Azure Key Vault存敏感配置确实是合规又安全的最佳实践,但偏偏ASP.NET Core的脚手架工具在这种场景下会“卡壳”,哪怕你操作的模型跟EF半毛钱关系都没有,照样给你报错。这事儿的根源其实很清晰:脚手架工具运行时会尝试完整初始化你的应用配置体系,但它没法读取你加到.gitignore里的本地JSON文件(毕竟那是你本地私有的,没进代码仓库),自然拿不到Key Vault的访问凭据,连带着整个配置加载流程崩掉,脚手架也就没法正常工作了。
下面给你几个实用的解决方案,按推荐程度排序:
方案1:给脚手架加个专属的配置 fallback
你可以在Program.cs里加个判断,检测当前是不是脚手架在运行,是的话就跳过Key Vault加载,改用临时的内存配置让应用初始化能正常走完。这样既不影响生产环境的逻辑,又能让脚手架顺利干活。
示例代码:
public static IWebHost BuildWebHost(string[] args) { // 检测是否是脚手架命令在运行 var isScaffolding = args.Any(arg => arg.Contains("scaffold") || arg.Contains("codegenerator")); var builder = WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { if (!isScaffolding) { // 原来的Key Vault加载逻辑不动 var localConfig = new ConfigurationBuilder() .AddJsonFile("local-secrets.json", optional: false, reloadOnChange: true) .Build(); var keyVaultClient = new KeyVaultClient( async (authority, resource, scope) => { var credential = new ClientCredential( localConfig["KeyVault:ClientId"], localConfig["KeyVault:ClientSecret"]); var authContext = new AuthenticationContext(authority); var result = await authContext.AcquireTokenAsync(resource, credential); return result.AccessToken; }); config.AddAzureKeyVault( $"https://{localConfig["KeyVault:VaultName"]}.vault.azure.net/", keyVaultClient, new DefaultKeyVaultSecretManager()); } else { // 脚手架模式下,用临时内存配置凑数,只要能让初始化过就行 config.AddInMemoryCollection(new Dictionary<string, string> { {"ConnectionStrings:YourDbContext", "Server=(localdb)\\mssqllocaldb;Database=TempScaffoldDb;Trusted_Connection=True;"} }); } }) .UseStartup<Startup>(); return builder.Build(); }
之后你再运行脚手架命令(比如dotnet aspnet-codegenerator controller -name TestController -m TestModel)时,程序会自动识别并切换到脚手架模式,配置加载不会再卡壳。
方案2:改用用户机密管理Key Vault凭据
ASP.NET Core自带的**用户机密(User Secrets)**是官方推荐的本地敏感信息管理方式,而且脚手架工具天生支持读取用户机密。你可以把原来存在本地JSON文件里的Key Vault应用ID和密码移到用户机密里,这样脚手架就能正常读取凭据、访问Key Vault,不需要改任何核心逻辑。
操作步骤:
- 进入项目目录,运行命令初始化用户机密:
dotnet user-secrets init
- 把Key Vault的凭据添加到用户机密:
dotnet user-secrets set "KeyVault:ClientId" "你的应用ID" dotnet user-secrets set "KeyVault:ClientSecret" "你的密码" dotnet user-secrets set "KeyVault:VaultName" "你的Key Vault名称"
- 修改
Program.cs里的配置读取逻辑,从用户机密获取凭据:
public static IWebHost BuildWebHost(string[] args) { return WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { // CreateDefaultBuilder已经自动加载了用户机密(开发环境下) var builtConfig = config.Build(); var keyVaultClient = new KeyVaultClient( async (authority, resource, scope) => { var credential = new ClientCredential( builtConfig["KeyVault:ClientId"], builtConfig["KeyVault:ClientSecret"]); var authContext = new AuthenticationContext(authority); var result = await authContext.AcquireTokenAsync(resource, credential); return result.AccessToken; }); config.AddAzureKeyVault( $"https://{builtConfig["KeyVault:VaultName"]}.vault.azure.net/", keyVaultClient, new DefaultKeyVaultSecretManager()); }) .UseStartup<Startup>() .Build(); }
这个方案更优雅,也符合官方的配置规范,以后本地开发的敏感信息都可以用用户机密来管理,不用再单独维护一个.gitignore的JSON文件。
方案3:临时注释Key Vault逻辑(紧急救急用)
如果你只是临时要做脚手架操作,不想折腾代码和配置,可以直接把Program.cs里加载Key Vault的代码注释掉,改用appsettings.Development.json里的本地连接字符串,做完脚手架操作后再恢复。不过这个方法比较粗暴,容易忘记恢复,只适合紧急情况。
内容的提问来源于stack exchange,提问作者Eric

