Начало работы с API защиты данных в ASP.NET Core
В основном защита данных состоит из следующих шагов:
- Создайте средство защиты данных от поставщика защиты данных.
- Вызовите метод с данными
Protect
, которые необходимо защитить. - Вызовите метод с данными
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!
*/
При создании предохранителя необходимо указать одну или несколько строк назначения. Строка назначения обеспечивает изоляцию между потребителями. Например, средство защиты, созданное со строкой назначения "зеленый", не сможет отменить защиту данных, предоставляемых защитником с целью "фиолетовый".
Совет
Экземпляры IDataProtectionProvider
и IDataProtector
являются потокобезопасными для нескольких вызывающих объектов. Предполагается, что после того, как компонент получает ссылку на IDataProtector
через вызов CreateProtector
, он будет использовать такую ссылку для нескольких вызовов Protect
и Unprotect
.
Вызов Unprotect
вызовет вызов CryptographicException, если защищенные полезные данные не могут быть проверены или расшифрованы. Некоторые компоненты могут игнорировать ошибки во время незащищенных операций; Компонент, который считывает файлы cookie проверки подлинности, может обрабатывать эту ошибку и обрабатывать запрос так, как если бы он не cookie имел вообще, а не завершился сбоем запроса. Компоненты, которые хотят, чтобы это поведение специально перехватывало CryptographicException, а не глотать все исключения.
Настройка пользовательского репозитория с помощью AddOptions
Рассмотрим следующий код, который использует поставщика услуг, так как реализация IXmlRepository
имеет зависимость от однотонной службы:
public void ConfigureServices(IServiceCollection services)
{
// ...
var sp = services.BuildServiceProvider();
services.AddDataProtection()
.AddKeyManagementOptions(o => o.XmlRepository = sp.GetService<IXmlRepository>());
}
Предыдущий код регистрирует следующее предупреждение:
Вызов BuildServiceProvider из кода приложения приводит к созданию дополнительной копии одноэлементных служб. В качестве параметров для Configure можно использовать альтернативные варианты, такие как службы внедрения зависимостей.
Следующий код предоставляет реализацию IXmlRepository
, не создавая поставщика услуг, поэтому создавая дополнительные копии одноэлементных служб:
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();
}
}
ASP.NET Core