Introducción a las API de protección de datos en ASP.NET Core
Básicamente, la protección de datos consta de los pasos siguientes:
- Cree un protector de datos a partir de un proveedor de protección de datos.
- Llame al
Protectmétodo con los datos que desea proteger. - Llame al
Unprotectmétodo con los datos que desea volver a convertir en texto sin formato.
La mayoría de los marcos y modelos de aplicaciones, como ASP.NET Core o , ya configuran el sistema de protección de datos y lo agregan a un contenedor de servicios al que se accede a través de la inserción SignalR de dependencias. En el ejemplo siguiente se muestra lo siguiente:
- Configuración de un contenedor de servicios para la inserción de dependencias y el registro de la pila de protección de datos.
- Recibir el proveedor de protección de datos a través de la DI.
- Crear un protector.
- Protección y desprotección de datos.
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!
*/
Al crear un protector, debe proporcionar una o varias cadenas de propósito. Una cadena de propósito proporciona aislamiento entre los consumidores. Por ejemplo, un protector creado con una cadena de propósito "verde" no podría desproteger los datos proporcionados por un protector con un propósito de "púrpura".
Sugerencia
Las instancias de IDataProtectionProvider y IDataProtector son seguras para subprocesos para varios llamadores. Se pretende que una vez que un componente obtiene una referencia a mediante una llamada a , usará esa referencia para varias llamadas a IDataProtector CreateProtector y Protect Unprotect .
Una llamada a produce cryptographicException si no se puede comprobar o descifrar la carga Unprotect protegida. Es posible que algunos componentes deseen omitir los errores durante las operaciones de desprotección. Un componente que lee los de autenticación podría controlar este error y tratar la solicitud como si no tuviera ninguna en lugar de producir un error directo en cookie cookie la solicitud. Los componentes que desean este comportamiento deben detectar específicamente CryptographicException en lugar de evitar todas las excepciones.
Uso de AddOptions para configurar un repositorio personalizado
Tenga en cuenta el código siguiente que usa un proveedor de servicios porque la implementación de IXmlRepository tiene una dependencia en un servicio singleton:
public void ConfigureServices(IServiceCollection services)
{
// ...
var sp = services.BuildServiceProvider();
services.AddDataProtection()
.AddKeyManagementOptions(o => o.XmlRepository = sp.GetService<IXmlRepository>());
}
El código anterior registra la advertencia siguiente:
Al llamar a "BuildServiceProvider" desde el código de la aplicación, se crea una copia adicional de los servicios singleton. Considere alternativas como servicios de inserción de dependencias como parámetros para "Configurar".
El código siguiente proporciona la implementación sin tener que compilar el proveedor de servicios y, por tanto, realizar copias IXmlRepository adicionales de los servicios singleton:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataProtectionDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
// Register XmlRepository for data protection.
services.AddOptions<KeyManagementOptions>()
.Configure<IServiceScopeFactory>((options, factory) =>
{
options.XmlRepository = new CustomXmlRepository(factory);
});
services.AddRazorPages();
}
El código anterior quita la llamada a GetService y oculta IConfigureOptions<T> .
El código siguiente muestra el repositorio XML personalizado:
using CustomXMLrepo.Data;
using Microsoft.AspNetCore.DataProtection.Repositories;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
public class CustomXmlRepository : IXmlRepository
{
private readonly IServiceScopeFactory factory;
public CustomXmlRepository(IServiceScopeFactory factory)
{
this.factory = factory;
}
public IReadOnlyCollection<XElement> GetAllElements()
{
using (var scope = factory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<DataProtectionDbContext>();
var keys = context.XmlKeys.ToList()
.Select(x => XElement.Parse(x.Xml))
.ToList();
return keys;
}
}
public void StoreElement(XElement element, string friendlyName)
{
var key = new XmlKey
{
Xml = element.ToString(SaveOptions.DisableFormatting)
};
using (var scope = factory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<DataProtectionDbContext>();
context.XmlKeys.Add(key);
context.SaveChanges();
}
}
}
El código siguiente muestra la clase XmlKey:
public class XmlKey
{
public Guid Id { get; set; }
public string Xml { get; set; }
public XmlKey()
{
this.Id = Guid.NewGuid();
}
}