ASP.NET Core 中数据保护的非 DI 感知情境
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 实例对于多个调用方来说是线程安全的。