具有实体框架“DefaultConnection”应用程序设置的Azure密钥保险库
我试图使用Azure密钥保管库来存储我的实体框架的web api连接字符串。理想情况下,我想避免将密钥库nuget包与我的数据访问代码结合在一起。我的DbContext类有两个构造函数:具有实体框架“DefaultConnection”应用程序设置的Azure密钥保险库
public MyDbContext() : base("DefaultConnection")
{ . . . }
public MyDbContext(string connectionString) : base(connectionString)
{ . . . }
我的代码使用参数的构造函数后者从web配置的连接字符串。有一些地方我实例化一个新的MyDbContext对象,它禁止使用注入的解决方案。
我所走的路线是建立在我的DbContext的静态属性与连接字符串定位:
public interface IConnectionStringLocator
{ string Get(); }
public class DefaultConnectionStringLocator : IConnectionStringLocator
{
public string Get()
{
return "DefaultConnection";
}
}
public static IConnectionStringLocator ConnectionStringLocator { get; set; } =
new DefaultConnectionStringLocator();
我的网页API项目具有的NuGet包检索关键金库的秘密。所以在我的Global.asax文件我有这样的:
protected void Application_Start()
{
MyDbContext.ConnectionStringLocator = new ConnectionStringLocator("DefaultConnection");
}
public class ConnectionStringLocator : IConnectionStringLocator
{
private readonly string _connectionStringName;
public ConnectionStringLocator(string connectionStringName)
{
this._connectionStringName = connectionStringName;
}
public string Get()
{
var keyVaultName = WebConfigurationManager.AppSettings.Get("KeyVaultName");
if (keyVaultName == "develop")
return _connectionStringName;
else
{
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient =
new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var defaultConnectionSecret =
keyVaultClient.GetSecretAsync($"https://{keyVaultName}.vault.azure.net/secrets/{this._connectionStringName}");
return defaultConnectionSecret.Result.Value;
}
}
}
我出版这和它的作品,但它并没有“感觉”的权利。
另一种选择是遵循这篇文章https://blog.falafel.com/keeping-secrets-with-azure-key-vault/,但它需要我将KeyVault API包与我的数据访问结合起来。
我在寻找反馈和方向。我应该补充一点,我想使用密钥保管库的原因是,它允许我有天蓝色的管理员,他们可以在线查看应用程序设置,而无需通过连接字符串访问sql数据库。新MSI实现
KeyVault资源:https://github.com/Azure-Samples/app-service-msi-keyvault-dotnet/
以下是我解决了这个,在这情况下,任何人绊倒。
创建了一个ConfigurationManager类,它首先尝试从密钥库中获取值,但在失败时使用WebConfigurationManager读取应用程序设置。
public static class ConfigurationManager
{
public static string KeyVaultName => WebConfigurationManager.AppSettings.Get("KeyVaultName");
private static readonly Dictionary<string, string> ConfigurationCache = new Dictionary<string, string>();
private static SecretBundle GetSecret(string secretName, string vaultName = null)
{
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient =
new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secretUri = $"https://{vaultName ?? KeyVaultName}.vault.azure.net/secrets/{secretName}";
var secret = keyVaultClient.GetSecretAsync(secretUri);
return secret.Result;
}
public static string GetAppSettingValue(string secretName, string vaultName = null)
{
vaultName = vaultName ?? KeyVaultName;
string key = $"{vaultName}:{secretName}";
string value;
if (ConfigurationCache.TryGetValue(key, out value))
return value;
if (string.IsNullOrEmpty(vaultName) || vaultName == "develop")
{
value = WebConfigurationManager.AppSettings.Get(secretName);
ConfigurationCache.Add(key, value);
return value;
}
var secret = GetSecret(secretName);
value = secret.Value;
ConfigurationCache.Add(key, value);
return value;
}
public static void SetAppSettingValue(string secretName, string value, string vaultName = null)
{
vaultName = vaultName ?? KeyVaultName;
string key = $"{vaultName}:{secretName}";
if (ConfigurationCache.ContainsKey(key))
ConfigurationCache[key] = value;
else
{
WebConfigurationManager.AppSettings[key] = value;
ConfigurationCache.Add(key, value);
}
}
public static string GetConnectionStringValue(string secretName, string vaultName = null)
{
vaultName = vaultName ?? KeyVaultName;
string key = $"{vaultName}:{secretName}";
string value;
if (ConfigurationCache.TryGetValue(key, out value))
return value;
if (string.IsNullOrEmpty(vaultName) || vaultName == "develop")
{
value = WebConfigurationManager.ConnectionStrings[secretName].ConnectionString;
ConfigurationCache.Add(key, value);
return value;
}
var secret = GetSecret(secretName);
value = secret.Value;
ConfigurationCache.Add(key, value);
return value;
}
}
然后在我的DbContext类我呼吁Configurationmanager.GetConnectionStringValue( “DefaultConnection”)。
public MyDbContext()
: base(ConfigurationManager.GetConnectionStringValue("DefaultConnection"))
{...}