Omówienie interfejsów API konsumentów dla platformy ASP.NET Core

Interfejsy IDataProtectionProvider i IDataProtector to podstawowe interfejsy, za pomocą których konsumenci korzystają z systemu ochrony danych. Znajdują się one w pakiecie Microsoft.AspNetCore.DataProtection.Abstractions .

IDataProtectionProvider

Interfejs dostawcy reprezentuje katalog główny systemu ochrony danych. Nie można ich używać bezpośrednio do ochrony ani wyłączania ochrony danych. Zamiast tego konsument musi uzyskać odwołanie do obiektu IDataProtector , wywołując IDataProtectionProvider.CreateProtector(purpose)metodę , gdzie celem jest ciąg opisujący zamierzony przypadek użycia konsumenta. Aby uzyskać więcej informacji na temat intencji tego parametru i sposobu wybierania odpowiedniej wartości, zobacz Ciągi przeznaczenia.

IDataProtector

Interfejs ochrony jest zwracany przez wywołanie metody CreateProtectori jest to ten interfejs, którego użytkownicy mogą używać do wykonywania operacji ochrony i usuwania ochrony.

Aby chronić fragment danych, przekaż dane do Protect metody . Podstawowy interfejs definiuje metodę, która konwertuje bajt [] -> bajt[], ale istnieje również przeciążenie (podane jako metoda rozszerzenia), które konwertuje ciąg -> ciąg. Zabezpieczenia oferowane przez dwie metody są identyczne; deweloper powinien wybrać, które przeciążenie jest najwygodniejsze dla ich przypadku użycia. Niezależnie od wybranego przeciążenia wartość zwracana przez metodę Protect jest teraz chroniona (zaszyfrowana i zabezpieczona przed naruszeniami), a aplikacja może wysłać ją do niezaufanego klienta.

Aby wyłączyć ochronę wcześniej chronionego elementu danych, przekaż chronione dane do Unprotect metody . (Istnieją przeciążenia oparte na bajtach[]i oparte na ciągach dla wygody deweloperów). Jeśli chroniony ładunek został wygenerowany przez wcześniejsze wywołanie dla Protect tego samego IDataProtectorobiektu , Unprotect metoda zwróci oryginalny niechroniony ładunek. Jeśli chroniony ładunek został naruszony lub został wygenerowany przez inną IDataProtectormetodę , Unprotect metoda zwróci wyjątek CryptographicException.

Pojęcie tej samej wartości w porównaniu z różnymi IDataProtector powiązaniami z koncepcją celu. Jeśli dwa IDataProtector wystąpienia zostały wygenerowane z tego samego katalogu głównego IDataProtectionProvider , ale za pośrednictwem różnych ciągów przeznaczenia w wywołaniu metody IDataProtectionProvider.CreateProtector, są traktowane jako różne funkcje ochrony, a jeden nie będzie mógł wyłączyć ochrony ładunków wygenerowanych przez drugą.

Korzystanie z tych interfejsów

W przypadku składnika obsługującego di, zamierzone użycie polega na tym, że składnik przyjmuje IDataProtectionProvider parametr w konstruktorze i że system DI automatycznie udostępnia tę usługę po utworzeniu wystąpienia składnika.

Uwaga

Niektóre aplikacje (takie jak aplikacje konsolowe lub aplikacje ASP.NET 4.x) mogą nie mieć możliwości stosowania mechanizmu opisanego tutaj. W przypadku tych scenariuszy zapoznaj się z dokumentem Scenariusze niezwiązane z di, aby uzyskać więcej informacji na temat uzyskiwania wystąpienia IDataProtection dostawcy bez przechodzenia przez di.

W poniższym przykładzie przedstawiono trzy pojęcia:

  1. Dodaj system ochrony danych do kontenera usługi,

  2. Używanie di do odbierania wystąpienia elementu IDataProtectionProvideri

  3. Tworzenie obiektu IDataProtector na podstawie elementu IDataProtectionProvider i używanie go w celu ochrony i wyrejechowania ochrony danych.

Aplikacja konsolowa

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!
 */

Aplikacja internetowa

Wywołaj metodę AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

Poniższy wyróżniony kod pokazuje, jak używać IDataProtector w kontrolerze:

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();
    }
    
    // ...

Pakiet Microsoft.AspNetCore.DataProtection.Abstractions zawiera metodę GetDataProtector rozszerzenia jako wygodę dewelopera. Hermetyzuje ona jako pojedynczą operację pobierania elementu IDataProtectionProvider od dostawcy usług i wywoływania metody IDataProtectionProvider.CreateProtector. W poniższym przykładzie pokazano jego użycie:

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}");
    }
}

Napiwek

IDataProtectionProvider Wystąpienia elementów i IDataProtector są bezpieczne wątkowo dla wielu wywołujących. Ma to na celu, że gdy składnik pobiera odwołanie do elementu IDataProtector za pośrednictwem wywołania CreateProtectormetody , będzie używać tego odwołania dla wielu wywołań do Protect i Unprotect. Wywołanie metody , aby zgłosić Unprotect wyjątek CryptographicException, jeśli nie można zweryfikować ani odszyfrować chronionego ładunku. Niektóre składniki mogą chcieć ignorować błędy podczas operacji usuwania ochrony; składnik, który odczytuje uwierzytelnianie cookie, może obsłużyć ten błąd i traktować żądanie tak, jakby w ogóle nie cookie miał, zamiast nie prowadzić żądania wprost. Składniki, które chcą tego zachowania, powinny przechwytywać wyjątek CryptographicException zamiast połykać wszystkie wyjątki.