Visão geral das APIs de consumidor para o ASP.NET Core
As interfaces IDataProtectionProvider
e IDataProtector
são as interfaces básicas por meio das quais os consumidores usam o sistema de proteção de dados. Elas estão localizadas no pacote Microsoft.AspNetCore.DataProtection.Abstractions.
IDataProtectionProvider
A interface do provedor representa a raiz do sistema de proteção de dados. Ela não pode ser usada diretamente para proteger ou desproteger dados. Em vez disso, o consumidor deve obter uma referência a um IDataProtector
chamando IDataProtectionProvider.CreateProtector(purpose)
, em que finalidade é uma cadeia de caracteres que descreve o caso de uso do consumidor pretendido. Consulte Cadeias de Caracteres de Finalidade para obter muito mais informações sobre a intenção desse parâmetro e como escolher um valor adequado.
IDataProtector
A interface do protetor é retornada por uma chamada para CreateProtector
, e é essa interface que os consumidores podem usar para executar operações de proteção e desproteção.
Para proteger uma parte dos dados, passe os dados para o método Protect
. A interface básica define um método que converte byte[] -> byte[], mas também há uma sobrecarga (fornecida como um método de extensão) que converte cadeia de caracteres -> cadeia de caracteres. A segurança oferecida pelos dois métodos é idêntica; o desenvolvedor deve escolher a sobrecarga que for mais conveniente para o seu caso de uso. Independentemente da sobrecarga escolhida, o valor retornado pelo método Protect agora está protegido (cifrado e inviolável), e o aplicativo pode enviá-lo a um cliente não confiável.
Para desproteger uma parte de dados protegida anteriormente, passe os dados protegidos para o método Unprotect
. (Há sobrecargas baseadas em bytes[]e em cadeia de caracteres para conveniência do desenvolvedor.) Se o conteúdo protegido tiver sido gerado por uma chamada anterior para Protect
nesse mesmo IDataProtector
, o método Unprotect
retornará o conteúdo desprotegido original. Se o conteúdo protegido tiver sido adulterado ou produzido por um diferente IDataProtector
, o método Unprotect
lançará uma CryptographicException.
O conceito de IDataProtector
igual vs. diferente está ligado ao conceito de finalidade. Se duas instâncias IDataProtector
foram geradas a partir da mesma raiz IDataProtectionProvider
, mas por meio de cadeias de caracteres de finalidade diferentes na chamada para IDataProtectionProvider.CreateProtector
, elas serão consideradas protetores diferentes, e uma não poderá desproteger cargas geradas pela outra.
Consumo dessas interfaces
Para um componente com reconhecimento de DI, o uso pretendido é que o componente receba um parâmetro IDataProtectionProvider
em seu construtor e que o sistema DI forneça automaticamente esse serviço quando o componente for instanciado.
Observação
Alguns aplicativos (como os aplicativos de console ou os aplicativos ASP.NET 4.x) podem não ter reconhecimento de DI e, portanto, não podem usar o mecanismo descrito aqui. Para esses cenários, consulte o documento Cenários sem reconhecimento de DI para informações sobre como obter uma instância de um provedor IDataProtection
sem passar pela DI.
A amostra a seguir demonstra três conceitos:
Adicionar o sistema de proteção de dados ao contêiner de serviço,
Usando a DI para receber uma instância de um
IDataProtectionProvider
, eCriar um
IDataProtector
a partir de umIDataProtectionProvider
e usá-lo para proteger e desproteger dados.
Aplicativo de console
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!
*/
Aplicativo Web
Chamada 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 código realçado a seguir mostra como usar IDataProtector em um controlador:
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 de extensão GetDataProtector como uma conveniência para o desenvolvedor. Ele encapsula em uma única operação tanto a recuperação de um IDataProtectionProvider do provedor de serviços quanto a chamada de IDataProtectionProvider.CreateProtector
. A amostra a seguir demonstra seu uso:
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}");
}
}
Dica
As instâncias de IDataProtectionProvider
e IDataProtector
são à prova de thread para vários chamadores. A intenção é que uma vez que um componente obtenha uma referência a um IDataProtector
por meio de uma chamada a CreateProtector
, ele usará essa referência para várias chamadas a Protect
e Unprotect
. Uma chamada a Unprotect
gerará CryptographicException se a carga protegida não puder ser verificada ou decifrada. Alguns componentes podem querer ignorar erros durante operações de desproteção; um componente que lê cookies de autenticações pode lidar com esse erro e tratar a solicitação como se não tivesse nenhum cookie, em vez de falhar a solicitação imediatamente. Os componentes que desejam esse comportamento devem capturar especificamente uma CryptographicException em vez de engolir todas as exceções.