ASP.NET Core 的使用者 API 概述

IDataProtectionProviderIDataProtector 接口是使用者使用数据保护系统的基本接口。 它们位于 Microsoft.AspNetCore.DataProtection.Abstractions 包中。

IDataProtectionProvider

提供程序接口表示数据保护系统的根。 它不能直接用于保护或取消保护数据。 相反,使用者必须通过调用 IDataProtectionProvider.CreateProtector(purpose) 来获取对 IDataProtector 的引用,其中 purpose 是描述预期的使用者用例的字符串。 有关此参数的意图以及如何选择适当的值的更多详细信息,请参阅目的字符串

IDataProtector

保护程序接口是通过调用 CreateProtector 返回的,使用者可以使用此接口来执行保护和取消保护操作。

若要保护一段数据,请将数据传递给 Protect 方法。 基本接口定义执行 byte[] -> byte[] 转换的方法,但也有执行 string -> string 转换的重载。 这两种方法提供的安全性完全相同,开发人员应选择最适合他们用例的重载。 无论选择哪种重载,Protect 方法返回的任何值现在都受保护(加密且防篡改),应用程序可以将它发送到不受信任的客户端。

若要取消对之前保护的数据片段的保护,请将受保护的数据传递给 Unprotect 方法。 (为了方便开发人员使用,存在基于 byte[] 和基于 string 的重载)如果受保护的有效负载由之前在此相同的 IDataProtector 上调用 Protect 生成,Unprotect 方法将返回未受保护的原始有效负载。 如果受保护的有效负载已被篡改或是由不同的 IDataProtector 生成的,Unprotect 方法将引发 CryptographicException。

相同和不同 IDataProtector 的概念与之前的目的概念相关。 如果两个 IDataProtector 实例是通过 IDataProtectionProvider.CreateProtector 调用中不同的目的字符串从相同的根 IDataProtectionProvider 生成的,它们则被视为不同的保护程序,其中一个保护程序将无法取消保护由另一个保护程序生成的有效负载。

使用这些接口

对于 DPI 感知的组件,预期的用法是组件采用其构造函数中的 IDataProtectionProvider 参数,使 DI 系统在组件实例化时自动提供此服务。

注意

某些应用程序(例如控制台应用程序或 ASP.NET 4.x 应用程序)可能不是 DPI 感知的应用程序,因此无法使用此处所述的机制。 对于这些方案,请参阅非 DI 感知方案文档,详细了解如何无需通过 DI 获取 IDataProtection 提供程序的实例。

以下示例演示了三个概念:

  1. 向服务容器添加数据保护系统

  2. 使用 DI 接收 IDataProtectionProvider 的实例,以及

  3. IDataProtectionProvider 创建 IDataProtector,并用它来保护和取消保护数据。

控制台应用

using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        // add data protection services
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection();
        var services = serviceCollection.BuildServiceProvider();

        // create an instance of MyClass using the service provider
        var instance = ActivatorUtilities.CreateInstance<MyClass>(services);
        instance.RunSample();
    }

    public class MyClass
    {
        IDataProtector _protector;

        // the 'provider' parameter is provided by DI
        public MyClass(IDataProtectionProvider provider)
        {
            _protector = provider.CreateProtector("Contoso.MyClass.v1");
        }

        public void RunSample()
        {
            Console.Write("Enter input: ");
            string input = Console.ReadLine();

            // protect the payload
            string protectedPayload = _protector.Protect(input);
            Console.WriteLine($"Protect returned: {protectedPayload}");

            // unprotect the payload
            string unprotectedPayload = _protector.Unprotect(protectedPayload);
            Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ
 * Unprotect returned: Hello world!
 */

Web 应用

Program.cs 中调用 AddDataProtection(IServiceCollection, Action<DataProtectionOptions>)

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDataProtection();

var app = builder.Build();

下面突出显示的代码演示了如何在控制器中使用 IDataProtector

public class HomeController : Controller
{
    private readonly IDataProtector _dataProtector;

    public HomeController(IDataProtectionProvider dataProtectionProvider)
    {
        _dataProtector = dataProtectionProvider.CreateProtector("HomeControllerPurpose");
    }

    // ...

    public IActionResult Privacy()
    {
        // The original data to protect
        string originalData = "original data";

        // Protect the data (encrypt)
        string protectedData = _dataProtector.Protect(originalData);
        Console.WriteLine($"Protected Data: {protectedData}");

        // Unprotect the data (decrypt)
        string unprotectedData = _dataProtector.Unprotect(protectedData);
        Console.WriteLine($"Unprotected Data: {unprotectedData}");

        return View();
    }
    
    // ...

为了方便开发人员使用,Microsoft.AspNetCore.DataProtection.Abstractions 包中有一个扩展方法 GetDataProtector。 它封装为一个操作,用于从服务提供程序检索 IDataProtectionProvider 并调用 IDataProtectionProvider.CreateProtector。 以下示例演示了它的用法:

using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
 
public class Program
{
    public static void Main(string[] args)
    {
        // add data protection services
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection();
        var services = serviceCollection.BuildServiceProvider();
 
        // get an IDataProtector from the IServiceProvider
        var protector = services.GetDataProtector("Contoso.Example.v2");
        Console.Write("Enter input: ");
        string input = Console.ReadLine();
 
        // protect the payload
        string protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");
 
        // unprotect the payload
        string unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
    }
}

提示

IDataProtectionProviderIDataProtector 的实例对于多个调用方来说是线程安全的。 其目的是,一旦组件通过调用 CreateProtector 获得对 IDataProtector 的引用,它将在多次调用 ProtectUnprotect 时使用该引用。 如果无法验证或解密受保护的有效负载,对 Unprotect 的调用将引发 CryptographicException。 某些组件可能希望在取消保护操作期间忽略错误;读取身份验证 cookie 的组件可能会处理此错误,并将请求视为根本没有 cookie,而不是让请求彻底失败。 需要此行为的组件应该专门捕获 CryptographicException,而不是吞并所有异常。