ASP.NET Core에서 데이터 보호 API 시작

기본적으로 데이터 보호는 다음 단계로 구성됩니다.

  1. 데이터 보호 공급자에서 데이터 보호기를 만듭니다.
  2. 보호하려는 데이터를 사용하여 Protect 메서드를 호출합니다.
  3. 일반 Unprotect 텍스트로 되돌리려는 데이터를 사용하여 메서드를 호출합니다.

대부분의 프레임워크 및 앱 모델(예: ASP.NET Core 또는 SignalR )은 이미 데이터 보호 시스템을 구성하고 종속성 주입을통해 액세스되는 서비스 컨테이너에 추가합니다. 다음 샘플에서는 다음을 보여줍니다.

  • 종속성 주입을 위한 서비스 컨테이너 구성 및 데이터 보호 스택 등록
  • DI를 통해 데이터 보호 공급자 수신
  • 보호기 만들기
  • 데이터를 보호한 다음 보호 해제합니다.
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!
 */

보호기를 만들 때 하나 이상의 용도 문자열 을제공해야 합니다. 용도 문자열은 소비자 간에 격리를 제공합니다. 예를 들어 용도 문자열 "녹색"으로 만든 보호기에서는 보호기에서 제공하는 데이터를 "자주색"으로 보호 해제할 수 없습니다.

IDataProtectionProviderIDataProtector 인스턴스는 여러 호출자에 대해 스레드에서 안전합니다. 구성 요소가 호출을 통해 에 대한 참조를 가져오면 및 에 IDataProtector CreateProtector 대한 여러 호출에 해당 참조를 Protect Unprotect 사용합니다.

에 대한 Unprotect 호출은 보호된 페이로드를 확인하거나 해독할 수 없는 경우 CryptographicException을 throw합니다. 일부 구성 요소는 보호 해제 작업 중에 오류를 무시하려고 할 수 있습니다. 인증 을 읽는 구성 요소는 cookie 이 오류를 처리하고 요청을 완전히 실패하는 대신 전혀 없는 것처럼 처리할 수 cookie 있습니다. 이 동작을 원하는 구성 요소는 모든 예외를 swallowing 하는 대신 System.security.cryptography.cryptographicexception를 명확 하 게 catch 해야 합니다.

AddOptions를 사용 하 여 사용자 지정 리포지토리 구성

의 구현이 IXmlRepository singleton 서비스에 종속 되어 있기 때문에 서비스 공급자를 사용 하는 다음 코드를 고려 합니다.

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

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

위의 코드는 다음과 같은 경고를 기록 합니다.

응용 프로그램 코드에서 ' BuildServiceProvider '를 호출 하면 singleton 서비스의 추가 복사본이 생성 됩니다. 종속성을 ' 구성 '에 대 한 매개 변수로 삽입 하는 등의 대안을 고려 합니다.

다음 코드는 IXmlRepository 서비스 공급자를 빌드하지 않고 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();
}

위의 코드는에 대 한 호출을 제거 하 GetService 고를 숨깁니다 IConfigureOptions<T> .

다음 코드에서는 사용자 지정 XML 리포지토리를 보여 줍니다.

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

다음 코드에서는 XmlKey 클래스를 보여 줍니다.

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

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