配置-非DI

非 DI 感知的情境中 ASP.NET Core 的数据保护

作者:Rick Anderson

ASP.NET Core 数据保护系统通常是添加到服务容器并且供通过依赖关系注入 (DI) 的从属组件。 但是,一些情况下,这不是可行的或所需,尤其是在现有应用程序导入系统。

若要支持这些方案中, Microsoft.AspNetCore.DataProtection.Extensions包提供了一个具体类型DataProtectionProvider,它提供了简单的方法来使用数据保护而不依赖于 DI。 DataProtectionProvider类型实现IDataProtectionProvider 构造DataProtectionProvider只需提供DirectoryInfo实例,以指示应存储提供程序的加密密钥的位置,如下面的代码示例中所示:

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder));

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8FWbAn6...ch3hAPm1NJA
 * Unprotect returned: Hello world!
 *
 * Press any key...
*/

默认情况下,DataProtectionProvider具体类型不会加密原始密钥材料之前将其保存到文件系统。 这是为了支持开发人员将指向网络共享和数据保护系统无法自动推断相应现有静态密钥加密机制的方案。

此外,DataProtectionProvider具体类型不会隔离应用默认情况下。 使用相同密钥的目录的所有应用可以都共享负载,只要他们目的参数匹配。

DataProtectionProvider构造函数接受的可选配置回调,可用于调整系统的行为。 下面的示例演示使用显式调用还原隔离SetApplicationName 该示例还演示了将系统配置为自动加密使用 Windows DPAPI 持久化的密钥。 如果目录指向 UNC 共享,你可能想要在所有相关计算机间分发共享的证书并将系统配置为使用基于证书的加密和调用ProtectKeysWithCertificate

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder),
            configuration =>
            {
                configuration.SetApplicationName("my app name");
                configuration.ProtectKeysWithDpapi();
            });

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

提示

实例DataProtectionProvider具体类型是创建开销很大。 如果应用程序将保留此类型的多个实例,并且如果他们正在使用相同的密钥存储目录,可能会降低应用程序性能。 如果使用DataProtectionProvider类型,我们建议在一次创建此类型以及它尽可能多地重复使用。 DataProtectionProvider类型和所有IDataProtector从它创建的实例是线程安全的多个调用方。

目录