Kom igång med Dataskydds-API:er i ASP.NET Core

I grund och botten består skyddet av data av följande steg:

  1. Skapa ett dataskydd från en dataskyddsprovider.
  2. Protect Anropa metoden med de data som du vill skydda.
  3. Unprotect Anropa metoden med de data som du vill omvandla tillbaka till oformaterad text.

De flesta ramverk och appmodeller, till exempel ASP.NET Core eller SignalR, konfigurerar redan dataskyddssystemet och lägger till det i en tjänstcontainer som nås via beroendeinmatning. Följande exempel visar:

  • Konfigurera en tjänstcontainer för beroendeinmatning och registrera dataskyddsstacken.
  • Mottagning av dataskyddsleverantören via DI.
  • Skapa ett skydd.
  • Skydda och ta sedan bort skyddet av data.
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!
 */

När du skapar ett skydd måste du ange en eller flera Purpose Strings. En ändamålssträng ger isolering mellan konsumenter. Till exempel skulle ett skydd som skapats med en syftessträng av "grön" inte kunna ta bort skyddet av data som tillhandahålls av ett skydd med syftet "lila".

Tips/Råd

Instanser av IDataProtectionProvider och IDataProtector är trådsäkra för flera anropare. Det är avsett att när en komponent hämtar en referens till en IDataProtector via ett anrop till CreateProtectoranvänder den referensen för flera anrop till Protect och Unprotect.

Ett anrop till Unprotect genererar CryptographicException om den skyddade nyttolasten inte kan verifieras eller dechiffreras. Vissa komponenter kanske vill ignorera fel under oskyddade åtgärder. en komponent som läser autentiseringscookies kan hantera det här felet och behandla begäran som om den inte alls hade någon cookie i stället för att misslyckas med begäran direkt. Komponenter som vill ha det här beteendet bör specifikt fånga CryptographicException i stället för att svälja alla undantag.

Använda AddOptions för att konfigurera en anpassad lagringsplats

Tänk på följande kod som använder en tjänstleverantör eftersom implementeringen av IXmlRepository har ett beroende på en singleton-tjänst.

public void ConfigureServices(IServiceCollection services)
{
    // ...

    var sp = services.BuildServiceProvider();
    services.AddDataProtection()
      .AddKeyManagementOptions(o => o.XmlRepository = sp.GetService<IXmlRepository>());
}

Föregående kod loggar följande varning:

Om du anropar "BuildServiceProvider" från programkoden skapas ytterligare en kopia av singleton-tjänster. Överväg alternativ, till exempel beroendeinjektion av tjänster som parametrar för "Konfigurera".

Följande kod tillhandahåller implementeringen IXmlRepository utan att behöva skapa tjänstleverantören och därför göra ytterligare kopior av singleton-tjänster:

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

Koden ovan tar bort anropet till GetService och döljer IConfigureOptions<T>.

Följande kod visar den anpassade XML-lagringsplatsen:

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

Följande kod visar klassen XmlKey:

public class XmlKey
{
    public Guid Id { get; set; }
    public string Xml { get; set; }

    public XmlKey()
    {
        this.Id = Guid.NewGuid();
    }
}