代码之家  ›  专栏  ›  技术社区  ›  Shamshiel

自定义jsonconfigurationprovider-asp.net core使用错误的实现

  •  3
  • Shamshiel  · 技术社区  · 7 年前

    我尝试实现一个名为“cryptographyconfigprovider”的自定义jsonconfigurationprovider,如果json是加密的,它会从流中解密json。

    我从jsonconfigurationprovider继承并实现了一个自定义加载方法。

    我在program.cs中这样使用它:

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

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

    但是,在此asp.net核心尝试再次访问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 回复  |  直到 7 年前
        1
  •  2
  •   David Gardiner    6 年前

    从.NET Core 2.0开始, appsettings.{env.EnvironmentName}.json 为您自动加载。如果您已经对它进行了加密,那么框架在解析它时可能会遇到问题。

    .ConfigureAppConfiguration((hostingContext, config) =>
    {
        ...
    
        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
    
        ...
    

    MetaPackages/src/Microsoft.AspNetCore/WebHost.cs

    我想给你的档案起个别的名字。

    我的团队最近实现的另一个解决方案是将机密移到app.config并使用 protected configuration 加密它。自定义配置提供程序读取应用程序设置(例如 Azure:ApiKey )并提供给核心框架。

        2
  •  1
  •   Scott Roberts    7 年前

    必须创建自定义提供程序并使用旧的学校xml配置文件来处理加密设置是疯狂的。这应该由imo框架来处理。

    同时,我的答案是 this question 是对设置文件中的值进行加密的非常简单和直接的方法。它使用现有的json提供程序、首选的.net核心加密技术,并且对di友好。

    希望有帮助!