Mulai menggunakan API Perlindungan Data di ASP.NET Core

Pada dasarnya, melindungi data terdiri dari langkah-langkah berikut:

  1. Buat pelindung data dari penyedia perlindungan data.
  2. Protect Panggil metode dengan data yang ingin Anda lindungi.
  3. Unprotect Panggil metode dengan data yang ingin Anda ubah kembali menjadi teks biasa.

Sebagian besar kerangka kerja dan model aplikasi, seperti ASP.NET Core atau SignalR, sudah mengonfigurasi sistem perlindungan data dan menambahkannya ke kontainer layanan yang diakses melalui injeksi dependensi. Contoh berikut menunjukkan:

  • Mengonfigurasi kontainer layanan untuk injeksi dependensi dan mendaftarkan tumpukan perlindungan data.
  • Menerima penyedia perlindungan data melalui DI.
  • Membuat pelindung.
  • Melindungi kemudian membuka proteksi 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!
 */

Saat membuat pelindung, Anda harus menyediakan satu atau beberapa String Tujuan. String tujuan menyediakan isolasi antara konsumen. Misalnya, pelindung yang dibuat dengan string tujuan "hijau" tidak akan dapat membuka proteksi data yang disediakan oleh pelindung dengan tujuan "ungu".

Tip

Instans IDataProtectionProvider dan IDataProtector aman untuk beberapa penelepon. Ini dimaksudkan bahwa setelah komponen mendapatkan referensi ke IDataProtector melalui panggilan ke CreateProtector, itu akan menggunakan referensi tersebut untuk beberapa panggilan ke Protect dan Unprotect.

Panggilan ke Unprotect akan melempar CryptographicException jika payload yang dilindungi tidak dapat diverifikasi atau diurai. Beberapa komponen mungkin ingin mengabaikan kesalahan selama operasi yang tidak terlindungi; komponen yang membaca autentikasi cookiemungkin menangani kesalahan ini dan memperlakukan permintaan seolah-olah tidak cookie memiliki sama sekali daripada gagal permintaan secara langsung. Komponen yang menginginkan perilaku ini harus secara khusus menangkap CryptographicException alih-alih menelan semua pengecualian.

Menggunakan AddOptions untuk mengonfigurasi repositori kustom

Pertimbangkan kode berikut yang menggunakan penyedia layanan karena implementasi IXmlRepository memiliki dependensi pada layanan singleton:

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

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

Kode sebelumnya mencatat peringatan berikut:

Memanggil 'BuildServiceProvider' dari kode aplikasi menghasilkan salinan tambahan layanan singleton yang dibuat. Pertimbangkan alternatif seperti layanan injeksi dependensi sebagai parameter untuk 'Konfigurasi'.

Kode berikut menyediakan IXmlRepository implementasi tanpa harus membangun penyedia layanan dan oleh karena itu membuat salinan tambahan layanan 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();
}

Kode sebelumnya menghapus panggilan ke GetService dan menyembunyikan IConfigureOptions<T>.

Kode berikut menunjukkan repositori XML kustom:

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

Kode berikut menunjukkan kelas XmlKey:

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

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