Introducción a las API de consumidor para ASP.NET Core
Las interfaces de IDataProtectionProvider
y IDataProtector
son las interfaces básicas a través de las cuales los consumidores utilizan el sistema de protección de datos. Se encuentran en el paquete Microsoft.AspNetCore.DataProtection.Abstractions .
IDataProtectionProvider
La interfaz del proveedor representa la raíz del sistema de protección de datos. No se puede usar directamente para proteger o desproteger datos. En su lugar, el consumidor debe obtener una referencia a un IDataProtector
llamando a IDataProtectionProvider.CreateProtector(purpose)
, donde el propósito es una cadena que describe el caso de uso previsto por el consumidor. Consulte Cadenas de propósito para obtener más información sobre la intención de este parámetro y cómo elegir un valor adecuado.
IDataProtector
La interfaz del protector se devuelve mediante una llamada a CreateProtector
, y es esta interfaz la que los consumidores pueden utilizar para realizar operaciones de protección y desprotección.
Para proteger un fragmento de datos, páselo al método Protect
. La interfaz básica define un método que convierte byte[] -> byte[], pero también hay una sobrecarga (proporcionada como un método de extensión) que convierte string -> string. La seguridad ofrecida por los dos métodos es idéntica; el desarrollador debe elegir la sobrecarga más conveniente para su caso de uso. Independientemente de la sobrecarga elegida, el valor devuelto por el método de protección está ahora protegido (cifrado y a prueba de manipulaciones), y la aplicación puede enviarlo a un cliente que no sea de confianza.
Para desproteger un fragmento de datos protegido anteriormente, pase los datos protegidos al método Unprotect
. (Hay sobrecargas basadas en bytes[] y basadas en cadenas para la comodidad del desarrollador). Si la carga protegida se generó mediante una llamada anterior a Protect
en este mismo IDataProtector
, el método Unprotect
devolverá la carga desprotegida original. Si la carga protegida se ha manipulado o se ha producido mediante otro IDataProtector
, el método Unprotect
iniciará CryptographicException.
El concepto de igual frente a diferente IDataProtector
está relacionado con el concepto de propósito. Si dos instancias de IDataProtector
se generaron a partir de la misma raíz IDataProtectionProvider
pero a través de diferentes cadenas de propósito en la llamada a IDataProtectionProvider.CreateProtector
, entonces se consideran protectores diferentes, y uno no podrá desproteger las cargas útiles generadas por el otro.
Consumo de estas interfaces
Para un componente compatible con DI, el uso previsto es que el componente toma un parámetro IDataProtectionProvider
en su constructor y que el sistema de inserción de dependencias proporciona automáticamente este servicio cuando se crea una instancia del componente.
Nota:
Es posible que algunas aplicaciones (como aplicaciones de consola o de ASP.NET 4.x) no sean compatibles con DI, por lo que no puede usar el mecanismo descrito aquí. Para estos escenarios, consulte el documento Escenarios no compatibles con DI para obtener más información sobre cómo obtener una instancia de un proveedor de IDataProtection
sin pasar por la inserción de dependencias.
En el ejemplo siguiente se muestran tres conceptos:
Agregue el sistema de protección de datos al contenedor de servicios,
Uso de DI para recibir una instancia de
IDataProtectionProvider
yCreación de un
IDataProtector
a partir de unIDataProtectionProvider
y su uso para proteger y desproteger datos.
Aplicación 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!
*/
Aplicación web
Llame a AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) en Program.cs
:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDataProtection();
var app = builder.Build();
El código resaltado siguiente muestra cómo usar IDataProtector en un 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();
}
// ...
El paquete Microsoft.AspNetCore.DataProtection.Abstractions
contiene un método GetDataProtector de extensión como comodidad para desarrolladores. Se encapsula como una sola operación que recupera un IDataProtectionProvider del proveedor de servicios y llama a IDataProtectionProvider.CreateProtector
. En el ejemplo siguiente se muestra su 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}");
}
}
Sugerencia
Las instancias de IDataProtectionProvider
y IDataProtector
son seguras para subprocesos para varios autores de llamada. La intención es que una vez que un componente obtiene una referencia a un IDataProtector
a través de una llamada a CreateProtector
, utilizará esa referencia para múltiples llamadas a Protect
y Unprotect
. Una llamada a Unprotect
iniciará CryptographicException si la carga protegida no se puede comprobar ni descifrar. Algunos componentes pueden querer ignorar los errores durante las operaciones de desprotección; un componente que lee cookies de autenticación podría manejar este error y tratar la solicitud como si no tuviera cookie en lugar de rechazar la solicitud directamente. Los componentes que quieran este comportamiento deberían atrapar específicamente CryptographicException en lugar de tragarse todas las excepciones.