ASP.NET Core 2(Identity
の有無にかかわらず)でCookie認証を使用すると、ユーザーの電子メールまたは名前が変更されたり、Cookieの存続期間中にアカウントが削除されたりする場合があります。そのため、 docs は、Cookieを検証する必要があると指摘しています。ドキュメントの例はコメントされています
ここで説明するアプローチは、すべてのリクエストでトリガーされます。これにより、アプリのパフォーマンスが大幅に低下する可能性があります。
だから私はクッキープリンシパルを検証するための最良のパターンは何であるか疑問に思っています。 Startup.cs
で行ったことは、OnValidatePrincipal
イベントにサブスクライブし、プリンシパルの有効性を確認することです。次のように、CookieにLastValidatedOn
クレームを追加して5分ごとに:
services.ConfigureApplicationCookie(options =>
{
// other cookie options go here
options.Events.OnValidatePrincipal = async context =>
{
const string claimType = "LastValidatedOn";
const int reValidateAfterMinutes = 5;
if (!(context.Principal?.Identity is ClaimsIdentity claimIdentity)) return;
if (!context.Principal.HasClaim(c => c.Type == claimType) ||
DateTimeOffset.Now.UtcDateTime.Subtract(new DateTime(long.Parse(context.Principal.Claims.First(c => c.Type == claimType).Value))) > TimeSpan.FromMinutes(reValidateAfterMinutes))
{
var mgr = context.HttpContext.RequestServices.GetRequiredService<SignInManager<ApplicationUser>>();
var user = await mgr.UserManager.FindByNameAsync(claimIdentity.Name);
if (user != null && claimIdentity.Claims.FirstOrDefault(c => c.Type == "AspNet.Identity.SecurityStamp")?.Value == await mgr.UserManager.GetSecurityStampAsync(user))
{
claimIdentity.FindAll(claimType).ToList().ForEach(c => claimIdentity.TryRemoveClaim(c));
claimIdentity.AddClaim(new Claim(claimType, DateTimeOffset.Now.UtcDateTime.Ticks.ToString(), typeof(long).ToString()));
context.ShouldRenew = true;
}
else
{
context.RejectPrincipal();
await mgr.SignOutAsync();
}
}
};
});
@MarkGは私を正しい方向に向けてくれました、ありがとう。 ソースコードSecurityStampValidator
とIdentity
を詳しく調べたところ、状況が明らかになりました。実際、質問とともに投稿したサンプルコードは不要です。これは、ASP.NET CoreIdentityが機能をすぐに使用できるようにするためです。
このような要約はまだ見つかりませんでしたので、他の人にも役立つかもしれません。
...しかしそれでも知っておくと良い...
_services.ConfigureApplicationCookie(options =>
{
options.Cookie.Expiration = TimeSpan.FromDays(30);
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.SlidingExpiration = true;
});
_
ExpireTimeSpan
デフォルトはTimeSpan.FromDays(14)
です。
認証チケットの発行時間はCookie(_CookieValidatePrincipalContext.Properties.IssuedUtc
_)の一部です。 Cookieがサーバーに返送されるとき、現在の時刻から発行時刻を引いた値は、ExpireTimeSpan
よりも大きい必要があります。そうでない場合、ユーザーはそれ以上の調査なしにサインアウトされます。実際には、ExpireTimeSpan
を設定すると、ほとんどの場合、SlidingExpiration
をtrue
に設定します。これは、ユーザーがアプリを積極的に操作していることを確認するための手段であり、デバイスを無人のままにします。負のTimeSpan
sは、ユーザーをすぐにサインオフします(ただし、_TimeSpan.Zero
_はサインオフしません)。
_services.AddOptions();
services.Configure<SecurityStampValidatorOptions>(options =>
{
// This is the key to control how often validation takes place
options.ValidationInterval = TimeSpan.FromMinutes(5);
});
_
デフォルトはTimeSpan.FromMinutes(30)
です。
これにより、認証Cookieの有効性が永続ストレージに対してチェックされるまでの期間が決まります。これは、サーバーへのすべてのリクエストに対してSecurityStampValidator
を呼び出すことによって実現されます。現在の時刻からCookieの発行時刻を引いた値が以下ValidationInterval
の場合、ValidateSecurityStampAsync
が呼び出されます。つまり、_ValidationInterval = TimeSpan.Zero
_は、リクエストごとにValidateSecurityStampAsync
を呼び出すことになります。
注UserManager
はセキュリティスタンプの取得をサポートする必要があります。サポートしていないと、失敗します。カスタムユーザーマネージャーまたはユーザーストアの場合、両方が_IUserSecurityStampStore<TUser>
_を適切に実装する必要があります。
Startup
でのサービスの読み込みシーケンス注意すべき点は次のとおりです。services. AddIdentity()
は、認証Cookieのデフォルトも設定します。 services.ConfigureApplicationCookie()
の後に追加すると、以前の設定が上書きされます。上記の前の関数の後にservices.Configure<SecurityStampValidatorOptions>()
を呼び出しました。
道を示してくれた@MarkGにもう一度感謝します。