自定义JsonConfigurationProvider - ASP.NET Core使用错误的实现

时间:2018-06-14 13:10:34

标签: c# asp.net-core asp.net-core-2.0

我试图实现一个名为'CryptographyConfigProvider'的自定义JsonConfigurationProvider,如果它被加密,它会从流中解密JSON。

我从JsonConfigurationProvider继承并实现了一个自定义的Load方法。

我在Program.cs中使用它:

  var configuration = new ConfigurationBuilder()
                .AddEncryptedJsonFile($"appsettings.{enviromentValue}.json", optional: true, reloadOnChange: false)
                .Build();

此调用执行我的自定义实现。 (见下文)

但是在此ASP.NET Core尝试再次访问appsettings文件之后:

 webHostBuilder.Build().Run();

异常表示调用了普通的JsonConfigurationProvider而不是我继承的类CryptographyConfigProvider。

System.FormatException: Could not parse the JSON file. Error on line number '0': 'EncryptedString'. 
---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: S. Path '', line 0, position 0.
at Newtonsoft.Json.JsonTextReader.ParseValue()
at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)
at Microsoft.Extensions.Configuration.Json.JsonConfigurationFileParser.Parse(Stream input)
at Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider.Load(Stream stream)
--- End of inner exception stack trace ---
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
at Main(String[] args) in Program.cs

有人知道为什么ASP.NET Core使用普通的JsonConfigurationProvider吗?

这是我的实施:

public static class DecryptionConfigProviderExtension
{
    public static IConfigurationBuilder AddEncryptedJsonFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
    {
        return builder.AddJsonFile(s =>
        {
            s.FileProvider = null;
            s.Path = path;
            s.Optional = optional;
            s.ReloadOnChange = reloadOnChange;
            s.ResolveFileProvider();
        });
    }

    public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action<CryptographyConfigurationSource> configureSource) => builder.Add(configureSource);
}

public class CryptographyConfigurationSource : JsonConfigurationSource, IConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        EnsureDefaults(builder);
        return new CryptographyConfigProvider(this);
    }
}

public class CryptographyConfigProvider : JsonConfigurationProvider
{
    private const string EncryptionKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";

    private AesCryptography _aesCryptography;

    public CryptographyConfigProvider(CryptographyConfigurationSource cryptographyConfigurationSource) : base(cryptographyConfigurationSource)
    {
        _aesCryptography = new AesCryptography();
    }

    public override void Load(Stream stream)
    {
        Data = UnencryptConfiguration(stream);
    }

    private IDictionary<string, string> UnencryptConfiguration(Stream stream)
    {
        var reader = new StreamReader(stream);
        var text = reader.ReadToEnd();
        var jsonString = DecryptIfEncrypted(text);

        using (MemoryStream jsonStream = new MemoryStream())
        {
            var parser = new JsonConfigurationFileParser();
            StreamWriter writer = new StreamWriter(jsonStream);
            writer.Write(jsonString);
            writer.Flush();
            jsonStream.Position = 0;
            return parser.Parse(jsonStream);
        };
    }

    private string DecryptIfEncrypted(string text)
    {
        var jsonString = string.Empty;

        try
        {
            jsonString = _aesCryptography.DecryptString(text, EncryptionKey);
        }
        catch
        {
            jsonString = text;
        }

        return jsonString;
    }
}

2 个答案:

答案 0 :(得分:2)

从.NET Core 2.0开始,Method doSomethingWithData:<OCMBlockConstraint: 0x7ff252a65a10> fromString:<OCMBlockConstraint: 0x7ff252a5f170> success:<OCMAnyConstraint: 0x7ff252a38350> failure:<OCMAnyConstraint: 0x7ff252a5f200> was not invoked.会自动加载。如果你已加密它,那么框架可能会解析它。

appsettings.{env.EnvironmentName}.json

MetaPackages/src/Microsoft.AspNetCore/WebHost.cs

我会尝试将您的文件命名为其他内容。

我的团队最近实施的另一种解决方案是将秘密移至app.config并使用protected configuration对其进行加密。自定义配置提供程序读取应用程序设置(例如.ConfigureAppConfiguration((hostingContext, config) => { ... config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); ... )并将它们提供给Core框架。

答案 1 :(得分:1)

必须创建自定义提供程序并使用老式的XML配置文件来处理加密设置,这很疯狂。这应该由IMO框架来处理。

同时,我对this question的回答是一种非常简单直接的方法,用于加密设置文件中的值。它使用现有的JSON提供程序,首选的.Net Core加密技术,并且对DI友好。

希望有帮助!