[ASP.NET Core]ASP.NET Core应用程序开发中如何加密配置文件(appsettings.json)或者配置文件的选项?

ASP.NET Core 作者: Rector 17阅读 0评论 0收藏 收藏本文

郑重申明:本文未经许可,禁止任何形式转载

问题描述

在ASP.NET WebForm或者ASP.NET MVC应用程序开发,我们可以将Web.config文件中涉及项目私密的信息进行加密存储,但在ASP.NET Core中没有了Web.config配置文件。如果要在ASP.NET Core保存加密配置信息,应该如何实现呢?appsettings.json配置文件是否可以加密呢?

方案一

ASP.NET Core中,我们可以实现自定义的配置方式CustomConfigProvider,如下:

public class CustomConfigProvider : ConfigurationProvider, IConfigurationSource
{
    public CustomConfigProvider()
    {

    }

    public override void Load()
    {
        Data = UnencryptMyConfiguration();
    }

    private IDictionary<string, string> UnencryptMyConfiguration()
    {
        // 这里可以以任何方式加载配置数据,只要最后将数据转换成如下形式的字典即可
       var configValues = new Dictionary<string, string>
       {
            {"key1", "unencryptedValue1"},
            {"key2", "unencryptedValue2"}
       };
       return configValues;
    }

    private IDictionary<string, string> CreateAndSaveDefaultValues(IDictionary<string, string> defaultDictionary)
    {
        var configValues = new Dictionary<string, string>
        {
            {"key1", "encryptedValue1"},
            {"key2", "encryptedValue2"}
        };
        return configValues;                
    }
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
       return new CustomConfigProvider();
    }
}

再定义一个IConfigurationBuilder的静态扩展方法,如下:

public static class CustomConfigProviderExtensions
{              
    public static IConfigurationBuilder AddEncryptedProvider(this IConfigurationBuilder builder)
    {
        return builder.Add(new CustomConfigProvider());
    }
}

最后,在启动类Startup.cs文件中配置即可,如下:

var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEncryptedProvider()
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

方案二

不创建自定义配置提供类,而利用JsonConfigurationProvider类来重写Load()方法,如下:

public class JsonConfigurationProvider2 : JsonConfigurationProvider
{
    public JsonConfigurationProvider2(JsonConfigurationSource2 source) : base(source)
    {
    }

    public override void Load(Stream stream)
    {
        base.Load(stream);

        // 读取配置文件需要的节点数据,然后解密
        // 请自已实现加密和解密的方法,这里未提供加密/解密的实现

         Data["abc:password"] = MyEncryptionLibrary.Decrypt(Data["abc:password"]);
    }
}

public class JsonConfigurationSource2 : JsonConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        EnsureDefaults(builder);
        return new JsonConfigurationProvider2(this);
    }
}

public static class JsonConfigurationExtensions2
{
    public static IConfigurationBuilder AddJsonFile2(this IConfigurationBuilder builder, string path, bool optional,
        bool reloadOnChange)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }
        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentException("File path must be a non-empty string.");
        }

        var source = new JsonConfigurationSource2
        {
            FileProvider = null,
            Path = path,
            Optional = optional,
            ReloadOnChange = reloadOnChange
        };

        source.ResolveFileProvider();
        builder.Add(source);
        return builder;
    }
}

然后,配置启动类Startup.cs,如下:

var builder = new ConfigurationBuilder()
            .AddJsonFile2($"appsettings.json", optional: true);

方案三

实现一个基于IServiceCollection接口的静态扩展方法,如下:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddProtectedConfiguration(this IServiceCollection services)
    {
        services
            .AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\keys"))
            .ProtectKeysWithDpapi();

        return services;
    }

    public static IServiceCollection ConfigureProtected<TOptions>(this IServiceCollection services, IConfigurationSection section) where TOptions: class, new()
    {
        return services.AddSingleton(provider =>
        {
            var dataProtectionProvider = provider.GetRequiredService<IDataProtectionProvider>();
            section = new ProtectedConfigurationSection(dataProtectionProvider, section);

            var options = section.Get<TOptions>();
            return Options.Create(options);
        });
    }

    private class ProtectedConfigurationSection : IConfigurationSection
    {
        private readonly IDataProtectionProvider _dataProtectionProvider;
        private readonly IConfigurationSection _section;
        private readonly Lazy<IDataProtector> _protector;

        public ProtectedConfigurationSection(
            IDataProtectionProvider dataProtectionProvider,
            IConfigurationSection section)
        {
            _dataProtectionProvider = dataProtectionProvider;
            _section = section;

            _protector = new Lazy<IDataProtector>(() => dataProtectionProvider.CreateProtector(section.Path));
        }

        public IConfigurationSection GetSection(string key)
        {
            return new ProtectedConfigurationSection(_dataProtectionProvider, _section.GetSection(key));
        }

        public IEnumerable<IConfigurationSection> GetChildren()
        {
            return _section.GetChildren()
                .Select(x => new ProtectedConfigurationSection(_dataProtectionProvider, x));
        }

        public IChangeToken GetReloadToken()
        {
            return _section.GetReloadToken();
        }

        public string this[string key]
        {
            get => GetProtectedValue(_section[key]);
            set => _section[key] = _protector.Value.Protect(value);
        }

        public string Key => _section.Key;
        public string Path => _section.Path;

        public string Value
        {
            get => GetProtectedValue(_section.Value);
            set => _section.Value = _protector.Value.Protect(value);
        }

        private string GetProtectedValue(string value)
        {
            if (value == null)
                return null;

            return _protector.Value.Unprotect(value);
        }
    }
}

在启动类Startup.cs中配置IServiceCollection服务,如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    // 注册常规的配置选项
    services.Configure<MySettings>(Configuration.GetSection("MySettings"));

    // 注册加密的配置选项
    services.AddProtectedConfiguration();
    services.ConfigureProtected<MyProtectedSettings>(Configuration.GetSection("MyProtectedSettings"));
}

在控制器中可以使用IDataProtectionProvider的实例来读取配置数据,如下:

[Route("encrypt"), HttpGet, HttpPost]
public string Encrypt(string section, string value)
{
    var protector = _dataProtectionProvider.CreateProtector(section);
    return protector.Protect(value);
}

阅读了该文章的人还浏览了...

本文永久链接码友网 » [ASP.NET Core]ASP.NET Core应用程序开发中如何加密配置文件(appsettings.json)或者配置文件的选项?

发布于: 2018-11-08 15:53:17
分享扩散: