非 DI 感知的情境中 ASP.NET Core 的数据保护Non-DI aware scenarios for Data Protection in ASP.NET Core
本文内容
ASP.NET Core 数据保护系统通常会添加到服务容器中,并通过依赖关系注入(DI)由从属组件使用。但是,在某些情况下,这种情况并不可行,尤其是将系统导入现有应用时。
为了支持这些方案, AspNetCore包提供了一个具体类型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实例对于多个调用方是线程安全的。