Partilhar via


Visão geral das APIs de consumo para ASP.NET Core

As interfaces IDataProtectionProvider e IDataProtector são as interfaces básicas através das quais os consumidores utilizam o sistema de proteção de dados. Estão localizados no pacote Microsoft.AspNetCore.DataProtection.Abstractions .

IDataProtectionProvider

A interface do fornecedor representa a raiz do sistema de proteção de dados. Não pode ser usada diretamente para proteger ou desproteger dados. Em vez disso, o consumidor deve obter uma referência a um IDataProtector ao chamar IDataProtectionProvider.CreateProtector(purpose), onde finalidade é uma cadeia que descreve o caso de uso pretendido pelo consumidor. Consulte Cadeias de Propósito para muito mais informações sobre a intenção deste parâmetro e como escolher um valor apropriado.

IDataProtector

A interface protetora é devolvida por uma chamada para CreateProtector, e é esta interface que os consumidores podem usar para realizar operações de proteção e desproteção.

Para proteger um dado, passe os dados ao Protect método. A interface básica define um método que converte byte[] -> byte[], mas também existe uma sobrecarga (fornecida como método de extensão) que converte string -> string. A segurança oferecida pelos dois métodos é idêntica; O programador deve escolher a sobrecarga que for mais conveniente para o seu caso de uso. Independentemente da sobrecarga escolhida, o valor devolvido pelo método Protect é agora protegido (cifrado e à prova de adulterações), e a aplicação pode enviá-lo para um cliente não confiável.

Para desproteger um dado previamente protegido, passe os dados protegidos para o Unprotect método. (Existem sobrecargas baseadas em bytes[] e em strings para conveniência do programador.) Se a carga útil protegida foi gerada por uma chamada anterior para Protect neste mesmo IDataProtector, o Unprotect método devolverá a carga útil original não protegida. Se a carga útil protegida tiver sido adulterada ou produzida por outro IDataProtector, o Unprotect método irá lançar CryptographicException.

O conceito de igual vs. diferente IDataProtector liga-se ao conceito de propósito. Se duas IDataProtector instâncias foram geradas a partir da mesma raiz IDataProtectionProvider mas através de cadeias de propósito diferentes na chamada para IDataProtectionProvider.CreateProtector, então são consideradas protetores diferentes, e uma não poderá desproteger cargas úteis geradas pela outra.

Consumo destas interfaces

Para um componente ciente de DI, o uso pretendido é que o componente aceite um parâmetro IDataProtectionProvider no seu construtor e que o sistema DI forneça automaticamente esse serviço quando o componente é instanciado.

Observação

Algumas aplicações (como aplicações de consola ou aplicações ASP.NET 4.x) podem não ser conscientes do DI, pelo que não podem usar o mecanismo aqui descrito. Para estes cenários, consulte o documento Cenários Não Conscientes de DI para obter mais informações sobre a forma de conseguir uma instância de um IDataProtection fornecedor sem passar por DI.

O exemplo seguinte demonstra três conceitos:

  1. Adicionar o sistema de proteção de dados ao contentor de serviço,

  2. Usando DI para receber uma instância de um IDataProtectionProvider e

  3. Criar um IDataProtector a partir de um IDataProtectionProvider e usá-lo para proteger e desproteger dados.

Aplicação de consola

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

Aplicação Web

Ligue AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) em Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

O seguinte código destacado mostra como usar IDataProtector num comando:

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

O pacote Microsoft.AspNetCore.DataProtection.Abstractions contém um método GetDataProtector de extensão como conveniência para o programador. Encapsula como uma única operação, tanto a recuperação de um IDataProtectionProvider do fornecedor de serviços como a chamada IDataProtectionProvider.CreateProtector. O exemplo seguinte demonstra a sua utilização:

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

Sugestão

Instâncias de IDataProtectionProvider e IDataProtector são "thread-safe" para múltiplas chamadas. Pretende-se que, uma vez que um componente recebe uma referência a an IDataProtector através de uma chamada para CreateProtector, ele use essa referência para múltiplas chamadas para Protect e Unprotect. Uma chamada para Unprotect lançará CryptographicException se a carga protegida não puder ser verificada ou decifrada. Alguns componentes podem querer ignorar erros durante operações sem proteção; um componente que lê cookies de autenticação pode tratar este erro e considerar o pedido como se não tivesse cookie de todo, em vez de rejeitar o pedido imediatamente. Os componentes que desejam este comportamento devem identificar especificamente o CryptographicException em vez de engolir todas as exceções.