ASP.NET Core Identity を使用せずに cookie 認証を使用する

作成者: Rick Anderson

ASP.NET Core Identity は、ログインを作成および管理するための、完全な機能を備えた認証プロバイダーです。 ただし、ASP.NET Core Identity を使用しない cookie ベースの認証プロバイダーを使用することができます。 詳細については、「ASP.NET Core の Identity の概要」を参照してください。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

サンプル アプリでのデモンストレーションのため、架空のユーザー Maria Rodriguez のユーザー アカウントがアプリにハードコーディングされています。 メール アドレス maria.rodriguez@contoso.com と任意のパスワードを使用して、ユーザーにサインインします。 ユーザーは、Pages/Account/Login.cshtml.cs ファイルの AuthenticateUser メソッドで認証されます。 実際の例では、ユーザーはデータストアに対して認証されます。

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();

builder.Services.AddHttpContextAccessor();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

AddAuthentication に渡される AuthenticationScheme によって、アプリの既定の認証方式が設定されます。 AuthenticationScheme は、cookie 認証の複数のインスタンスがあり、アプリで特定の方式の承認を行う必要がある場合に便利です。 AuthenticationSchemeCookieAuthenticationDefaults.AuthenticationScheme に設定すると、スキームの値は "Cookies" になります。 スキームを区別する任意の文字列値を使用できます。

アプリの認証方式は、アプリの cookie 認証方式とは異なります。 AddCookie に cookie の認証スキームが提供されていない場合は、CookieAuthenticationDefaults.AuthenticationScheme が使われます。 CookieAuthenticationDefaults.AuthenticationScheme GitHub ソースは、"Cookies" に設定されている例です。

認証 cookie の IsEssential プロパティは、既定で true に設定されます。 サイト ビジターがデータ収集に同意していない場合、認証 Cookie が許可されます。 詳細については、「General Data Protection Regulation (GDPR) support in ASP.NET Core」(ASP.NET Core での一般データ保護規則 (GDPR) のサポート) をご覧ください。

認証プロバイダーのオプションを構成するには、CookieAuthenticationOptions クラスを使用します。

メソッド AddCookieCookieAuthenticationOptions を構成します。

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
        options.SlidingExpiration = true;
        options.AccessDeniedPath = "/Forbidden/";
    });

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Cookie ポリシー ミドルウェア (GitHub ソース) UseCookiePolicy を使うと、cookie ポリシー機能を有効にすることができます。 ミドルウェアは、追加された順序で処理されます。

app.UseCookiePolicy(cookiePolicyOptions);

cookie 処理のグローバル特性を制御し、Cookie が追加または削除されたときに cookie 処理ハンドラーにフックするには、Cookie ポリシー ミドルウェアに提供される CookiePolicyOptions を使用します。

MinimumSameSitePolicy の既定値は SameSiteMode.Lax で、OAuth2 認証を許可します。 SameSiteMode.Strict と同じサイト ポリシーを厳密に適用するには、MinimumSameSitePolicy を設定します。 これを設定すると、OAuth2 や他のクロスオリジン認証方式は機能しなくなりますが、クロスオリジン要求処理に依存しない他の種類のアプリの cookie セキュリティのレベルが上がります。

var cookiePolicyOptions = new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
};

MinimumSameSitePolicy に対する Cookie ポリシー ミドルウェアの設定は、次の表に従って、CookieAuthenticationOptions の設定における Cookie.SameSite の設定に影響する場合があります。

MinimumSameSitePolicy Cookie.SameSite 結果の Cookie.SameSite の設定
SameSiteMode.None SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict

ユーザー情報を保持する cookie を作成するには、ClaimsPrincipal を構築します。 ユーザー情報は、シリアル化されて cookie に格納されます。

任意の必要な Claim を使用して ClaimsIdentity を作成し、SignInAsync を呼び出してユーザーをサインインさせます。 サンプル アプリの Login.cshtml.cs には、次のコードが含まれています。

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    ReturnUrl = returnUrl;

    if (ModelState.IsValid)
    {
        // Use Input.Email and Input.Password to authenticate the user
        // with your custom authentication logic.
        //
        // For demonstration purposes, the sample validates the user
        // on the email address maria.rodriguez@contoso.com with 
        // any password that passes model validation.

        var user = await AuthenticateUser(Input.Email, Input.Password);

        if (user == null)
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, user.Email),
            new Claim("FullName", user.FullName),
            new Claim(ClaimTypes.Role, "Administrator"),
        };

        var claimsIdentity = new ClaimsIdentity(
            claims, CookieAuthenticationDefaults.AuthenticationScheme);

        var authProperties = new AuthenticationProperties
        {
            //AllowRefresh = <bool>,
            // Refreshing the authentication session should be allowed.

            //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
            // The time at which the authentication ticket expires. A 
            // value set here overrides the ExpireTimeSpan option of 
            // CookieAuthenticationOptions set with AddCookie.

            //IsPersistent = true,
            // Whether the authentication session is persisted across 
            // multiple requests. When used with cookies, controls
            // whether the cookie's lifetime is absolute (matching the
            // lifetime of the authentication ticket) or session-based.

            //IssuedUtc = <DateTimeOffset>,
            // The time at which the authentication ticket was issued.

            //RedirectUri = <string>
            // The full path or absolute URI to be used as an http 
            // redirect response value.
        };

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme, 
            new ClaimsPrincipal(claimsIdentity), 
            authProperties);

        _logger.LogInformation("User {Email} logged in at {Time}.", 
            user.Email, DateTime.UtcNow);

        return LocalRedirect(Url.GetLocalUrl(returnUrl));
    }

    // Something failed. Redisplay the form.
    return Page();
}

コードのコメントを英語以外の言語に翻訳し表示したい場合、こちらの GitHub ディスカッション イシューにてお知らせください。

SignInAsync によって暗号化された cookie が作成されて、現在の応答に追加されます。 AuthenticationScheme が指定されていない場合は、既定の方式が使用されます。

RedirectUri は、既定では少数の特定のパス (ログイン パスやログアウト パスなど) でのみ使用されます。 詳細については、「CookieAuthenticationHandler の ソース」をご覧ください。

暗号化には、ASP.NET Core のデータ保護システムが使用されます。 複数のコンピューターでホストされているアプリの場合、アプリ間で負荷を分散する場合、または Web ファームを使用する場合は、同じキー リングとアプリ識別子を使用するように、データ保護を構成します。

サインアウト

現在のユーザーをサインアウトさせてその cookie を削除するには、SignOutAsync を呼び出します。

public async Task OnGetAsync(string returnUrl = null)
{
    if (!string.IsNullOrEmpty(ErrorMessage))
    {
        ModelState.AddModelError(string.Empty, ErrorMessage);
    }

    // Clear the existing external cookie
    await HttpContext.SignOutAsync(
        CookieAuthenticationDefaults.AuthenticationScheme);

    ReturnUrl = returnUrl;
}

スキームとして CookieAuthenticationDefaults.AuthenticationScheme または 「Cookie」が使用されていない場合は、認証プロバイダーを構成するときに使用するスキームを指定します。 それ以外の場合は、既定の方式が使用されます。 たとえば、スキームとして「ContosoCookie」を使用する場合は、認証プロバイダーを構成するときに使用するスキームを指定します。

ブラウザーが閉じられると、セッション ベースの cookie (非永続的な cookie) は自動的に削除されますが、個々のタブが閉じられたときは、cookie はクリアされません。 サーバーには、タブまたはブラウザーが閉じられたイベントは通知されません。

バックエンドの変更に対応する

cookie が作成されると、cookie が identity の唯一のソースになります。 バックエンド システムでユーザー アカウントが無効にされた場合:

  • アプリの cookie 認証システムによる要求の処理は、認証 cookie に基づいて続けられます。
  • 認証 cookie が有効である限り、ユーザーはアプリにサインインしたままになります。

ValidatePrincipal イベントを使用して、cookieidentity の検証をインターセプトし、オーバーライドすることができます。 すべての要求で cookie を検証すると、取り消されたユーザーがアプリにアクセスするリスクが軽減されます。

cookie を検証する方法の 1 つは、ユーザー データベースの変更を追跡することです。 ユーザーの cookie が発行された後でデータベースが変更されていない場合は、その cookie がまだ有効であれば、再認証を行う必要はありません。 サンプル アプリでは、データベースは IUserRepository に実装され、そこに LastChanged の値が格納されます。 データベースでユーザーが更新されると、LastChanged の値に現在時刻が設定されます。

LastChanged の値に基づいてデータベースが変更されたときに cookie を無効にするには、データベースの現在の LastChanged の値を含む LastChanged クレームを使用して cookie を作成します。

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("LastChanged", {Database Value})
};

var claimsIdentity = new ClaimsIdentity(
    claims,
    CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity));

ValidatePrincipal イベントのオーバーライドを実装するには、CookieAuthenticationEvents から派生するクラスに次のシグネチャを持つメソッドを記述します。

ValidatePrincipal(CookieValidatePrincipalContext)

CookieAuthenticationEvents の実装例を次に示します。

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    private readonly IUserRepository _userRepository;

    public CustomCookieAuthenticationEvents(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        var userPrincipal = context.Principal;

        // Look for the LastChanged claim.
        var lastChanged = (from c in userPrincipal.Claims
                           where c.Type == "LastChanged"
                           select c.Value).FirstOrDefault();

        if (string.IsNullOrEmpty(lastChanged) ||
            !_userRepository.ValidateLastChanged(lastChanged))
        {
            context.RejectPrincipal();

            await context.HttpContext.SignOutAsync(
                CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

cookie サービスの登録中にイベント インスタンスを登録します。 CustomCookieAuthenticationEvents クラスに対してスコープ指定されたサービスの登録を提供します。

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.EventsType = typeof(CustomCookieAuthenticationEvents);
    });

builder.Services.AddScoped<CustomCookieAuthenticationEvents>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

ユーザーの名前が更新される場合について考えます。これは、セキュリティにまったく影響を与えない決定です。 ユーザー プリンシパルを非破壊的に更新したい場合は、context.ReplacePrincipal を呼び出し、context.ShouldRenew プロパティを true に設定します。

警告

ここで説明するアプローチは、すべての要求でトリガーされます。 すべての要求ですべてのユーザーについて認証 cookie を検証すると、アプリのパフォーマンスが大幅に低下する可能性があります。

永続的 cookie

cookie をブラウザー セッション間で永続化することができます。 この永続化は、サインイン時の "アカウントを記憶する" チェック ボックスや同様のメカニズムによって、ユーザーの明示的な同意がある場合にのみ有効にする必要があります。

次のコード スニペットでは、ブラウザーを閉じても保持される identity および対応する cookie が作成されます。 以前に構成されたスライド式有効期限の設定が尊重されます。 ブラウザーが閉じられている間に cookie の有効期限が切れると、ブラウザーの再起動時に cookie はクリアされます。

AuthenticationPropertiesIsPersistenttrue に設定します。

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true
    });

ExpiresUtc を使用して、絶対的な有効期限を設定できます。 永続的な cookie を作成するには、IsPersistent も設定する必要があります。 そうしないと、cookie はセッション ベースの有効期間で作成され、保持されている認証チケットの前または後に期限切れになる可能性があります。 ExpiresUtc が設定されていると、CookieAuthenticationOptionsExpireTimeSpan オプションの値が設定されている場合はオーバーライドされます。

次のコード スニペットでは、有効期間が 20 分の identity および対応する cookie が作成されます。 これにより、以前に構成されたスライド式有効期限の設定はすべて無視されます。

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true,
        ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
    });

ASP.NET Core Identity は、ログインを作成および管理するための、完全な機能を備えた認証プロバイダーです。 ただし、ASP.NET Core Identity を使用しない cookie ベースの認証プロバイダーを使用することができます。 詳細については、「ASP.NET Core の Identity の概要」を参照してください。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

サンプル アプリでのデモンストレーションのため、架空のユーザー Maria Rodriguez のユーザー アカウントがアプリにハードコーディングされています。 メール アドレス maria.rodriguez@contoso.com と任意のパスワードを使用して、ユーザーにサインインします。 ユーザーは、Pages/Account/Login.cshtml.cs ファイルの AuthenticateUser メソッドで認証されます。 現実の例では、ユーザーはデータベースに対して認証されます。

構成

Startup.ConfigureServices メソッドでは、AddAuthentication および AddCookie メソッドを使用して認証ミドルウェア サービスが作成されます。

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();

AddAuthentication に渡される AuthenticationScheme によって、アプリの既定の認証方式が設定されます。 AuthenticationScheme は、cookie 認証の複数のインスタンスがあり、特定の方式で承認を行う場合に便利です。 AuthenticationSchemeCookieAuthenticationDefaults.AuthenticationScheme に設定すると、スキームに 「Cookies」の値が提供されます。 方式を区別する任意の文字列値を指定できます。

アプリの認証方式は、アプリの cookie 認証方式とは異なります。 cookie 認証スキームが AddCookie に提供されていない場合は、CookieAuthenticationDefaults.AuthenticationScheme (「Cookie」) が使用されます。

認証 cookie の IsEssential プロパティは、既定で true に設定されます。 サイト ビジターがデータ収集に同意していない場合、認証 Cookie が許可されます。 詳細については、「General Data Protection Regulation (GDPR) support in ASP.NET Core」(ASP.NET Core での一般データ保護規則 (GDPR) のサポート) をご覧ください。

Startup.Configure で、UseAuthenticationUseAuthorization を呼び出して HttpContext.User プロパティを設定し、要求に対して認可ミドルウェアを実行します。 UseEndpoints を呼び出す前に、UseAuthentication および UseAuthorization メソッドを呼び出します。

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

認証プロバイダーのオプションを構成するには、CookieAuthenticationOptions クラスを使用します。

Startup.ConfigureServices メソッドの認証用のサービス構成で CookieAuthenticationOptions を設定します。

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        ...
    });

Cookie ポリシー ミドルウェアを使用すると、cookie ポリシー機能が有効になります。 アプリ処理パイプラインへのミドルウェアの追加は順序に依存しており、パイプラインに登録されている下流コンポーネントにのみ影響が及びます。

app.UseCookiePolicy(cookiePolicyOptions);

cookie 処理のグローバル特性を制御し、Cookie が追加または削除されたときに cookie 処理ハンドラーにフックするには、Cookie ポリシー ミドルウェアに提供される CookiePolicyOptions を使用します。

MinimumSameSitePolicy の既定値は SameSiteMode.Lax で、OAuth2 認証を許可します。 SameSiteMode.Strict と同じサイト ポリシーを厳密に適用するには、MinimumSameSitePolicy を設定します。 これを設定すると、OAuth2 や他のクロスオリジン認証方式は機能しなくなりますが、クロスオリジン要求処理に依存しない他の種類のアプリの cookie セキュリティのレベルが上がります。

var cookiePolicyOptions = new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
};

MinimumSameSitePolicy に対する Cookie ポリシー ミドルウェアの設定は、次の表に従って、CookieAuthenticationOptions の設定における Cookie.SameSite の設定に影響する場合があります。

MinimumSameSitePolicy Cookie.SameSite 結果の Cookie.SameSite の設定
SameSiteMode.None SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict

ユーザー情報を保持する cookie を作成するには、ClaimsPrincipal を構築します。 ユーザー情報は、シリアル化されて cookie に格納されます。

任意の必要な Claim を使用して ClaimsIdentity を作成し、SignInAsync を呼び出してユーザーをサインインさせます。

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("FullName", user.FullName),
    new Claim(ClaimTypes.Role, "Administrator"),
};

var claimsIdentity = new ClaimsIdentity(
    claims, CookieAuthenticationDefaults.AuthenticationScheme);

var authProperties = new AuthenticationProperties
{
    //AllowRefresh = <bool>,
    // Refreshing the authentication session should be allowed.

    //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
    // The time at which the authentication ticket expires. A 
    // value set here overrides the ExpireTimeSpan option of 
    // CookieAuthenticationOptions set with AddCookie.

    //IsPersistent = true,
    // Whether the authentication session is persisted across 
    // multiple requests. When used with cookies, controls
    // whether the cookie's lifetime is absolute (matching the
    // lifetime of the authentication ticket) or session-based.

    //IssuedUtc = <DateTimeOffset>,
    // The time at which the authentication ticket was issued.

    //RedirectUri = <string>
    // The full path or absolute URI to be used as an http 
    // redirect response value.
};

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity), 
    authProperties);

コードのコメントを英語以外の言語に翻訳し表示したい場合、こちらの GitHub ディスカッション イシューにてお知らせください。

SignInAsync によって暗号化された cookie が作成されて、現在の応答に追加されます。 AuthenticationScheme が指定されていない場合は、既定の方式が使用されます。

RedirectUri は、既定では少数の特定のパス (ログイン パスやログアウト パスなど) でのみ使用されます。 詳細については、「CookieAuthenticationHandler の ソース」をご覧ください。

暗号化には、ASP.NET Core のデータ保護システムが使用されます。 複数のコンピューターでホストされているアプリの場合、アプリ間で負荷を分散する場合、または Web ファームを使用する場合は、同じキー リングとアプリ識別子を使用するように、データ保護を構成します。

サインアウト

現在のユーザーをサインアウトさせてその cookie を削除するには、SignOutAsync を呼び出します。

await HttpContext.SignOutAsync(
    CookieAuthenticationDefaults.AuthenticationScheme);

CookieAuthenticationDefaults.AuthenticationScheme (または「Cookies」) がスキームとして使用されていない場合は、 (「ContosoCookie」など)、認証プロバイダーを構成するときに使用するスキームを指定します。 それ以外の場合は、既定の方式が使用されます。

ブラウザーが閉じられると、セッション ベースの cookie (非永続的な cookie) は自動的に削除されますが、個々のタブが閉じられたときは、cookie はクリアされません。 サーバーには、タブまたはブラウザーが閉じられたイベントは通知されません。

バックエンドの変更に対応する

cookie が作成されると、cookie が identity の唯一のソースになります。 バックエンド システムでユーザー アカウントが無効にされた場合:

  • アプリの cookie 認証システムによる要求の処理は、認証 cookie に基づいて続けられます。
  • 認証 cookie が有効である限り、ユーザーはアプリにサインインしたままになります。

ValidatePrincipal イベントを使用して、cookieidentity の検証をインターセプトし、オーバーライドすることができます。 すべての要求で cookie を検証すると、取り消されたユーザーがアプリにアクセスするリスクが軽減されます。

cookie を検証する方法の 1 つは、ユーザー データベースの変更を追跡することです。 ユーザーの cookie が発行された後でデータベースが変更されていない場合は、その cookie がまだ有効であれば、再認証を行う必要はありません。 サンプル アプリでは、データベースは IUserRepository に実装され、そこに LastChanged の値が格納されます。 データベースでユーザーが更新されると、LastChanged の値に現在時刻が設定されます。

LastChanged の値に基づいてデータベースが変更されたときに cookie を無効にするには、データベースの現在の LastChanged の値を含む LastChanged クレームを使用して cookie を作成します。

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("LastChanged", {Database Value})
};

var claimsIdentity = new ClaimsIdentity(
    claims, 
    CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity));

ValidatePrincipal イベントのオーバーライドを実装するには、CookieAuthenticationEvents から派生するクラスに次のシグネチャを持つメソッドを記述します。

ValidatePrincipal(CookieValidatePrincipalContext)

CookieAuthenticationEvents の実装例を次に示します。

using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    private readonly IUserRepository _userRepository;

    public CustomCookieAuthenticationEvents(IUserRepository userRepository)
    {
        // Get the database from registered DI services.
        _userRepository = userRepository;
    }

    public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        var userPrincipal = context.Principal;

        // Look for the LastChanged claim.
        var lastChanged = (from c in userPrincipal.Claims
                           where c.Type == "LastChanged"
                           select c.Value).FirstOrDefault();

        if (string.IsNullOrEmpty(lastChanged) ||
            !_userRepository.ValidateLastChanged(lastChanged))
        {
            context.RejectPrincipal();

            await context.HttpContext.SignOutAsync(
                CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

Startup.ConfigureServices メソッドで cookie サービスを登録する間にイベント インスタンスを登録します。 CustomCookieAuthenticationEvents クラスに対してスコープ指定されたサービスの登録を提供します。

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.EventsType = typeof(CustomCookieAuthenticationEvents);
    });

services.AddScoped<CustomCookieAuthenticationEvents>();

ユーザーの名前が更新される場合について考えます。これは、セキュリティにまったく影響を与えない決定です。 ユーザー プリンシパルを非破壊的に更新したい場合は、context.ReplacePrincipal を呼び出し、context.ShouldRenew プロパティを true に設定します。

警告

ここで説明するアプローチは、すべての要求でトリガーされます。 すべての要求ですべてのユーザーについて認証 cookie を検証すると、アプリのパフォーマンスが大幅に低下する可能性があります。

永続的 cookie

cookie をブラウザー セッション間で永続化することができます。 この永続化は、サインイン時の "アカウントを記憶する" チェック ボックスや同様のメカニズムによって、ユーザーの明示的な同意がある場合にのみ有効にする必要があります。

次のコード スニペットでは、ブラウザーを閉じても保持される identity および対応する cookie が作成されます。 以前に構成されたスライド式有効期限の設定が尊重されます。 ブラウザーが閉じられている間に cookie の有効期限が切れると、ブラウザーの再起動時に cookie はクリアされます。

AuthenticationPropertiesIsPersistenttrue に設定します。

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true
    });

ExpiresUtc を使用して、絶対的な有効期限を設定できます。 永続的な cookie を作成するには、IsPersistent も設定する必要があります。 そうしないと、cookie はセッション ベースの有効期間で作成され、保持されている認証チケットの前または後に期限切れになる可能性があります。 ExpiresUtc が設定されていると、CookieAuthenticationOptionsExpireTimeSpan オプションの値が設定されている場合はオーバーライドされます。

次のコード スニペットでは、有効期間が 20 分の identity および対応する cookie が作成されます。 これにより、以前に構成されたスライド式有効期限の設定はすべて無視されます。

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true,
        ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
    });