2017-09-20 29 views
1

我试图使用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/

回答

0

以下是我解决了这个,在这情况下,任何人绊倒。

创建了一个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")) 
    {...} 
相关问题