ASP.NET Core でデータ保護 API の使用を開始する
基本的に、データの保護は次の手順で構成されます。
- データ保護プロバイダーからデータ プロテクターを作成します。
- 保護するデータを使用して
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!
*/
プロテクターを作成する場合は、1 つ以上の目的文字列を指定する必要があります。 目的文字列により、コンシューマー間が分離されます。 たとえば、"green" という目的文字列を使用して作成されたプロテクターでは、"purple" を目的としたプロテクターによって提供されるデータの保護を解除することはできません。
ヒント
IDataProtectionProvider
と IDataProtector
のインスタンスは、複数の呼び出し元に対してスレッドセーフです。 これは、コンポーネントが CreateProtector
への呼び出しによって IDataProtector
への参照を取得すると、その参照が 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