共用方式為


不透過 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();

AuthenticationScheme 傳遞給 AddAuthentication 設定應用程式的預設驗證配置。 當有多個 cookie 驗證執行個體,且應用程式需要以特定配置進行授權時,AuthenticationScheme 會很有用。 將 AuthenticationScheme 設定為 CookieAuthenticationDefaults.AuthenticationScheme 會為配置提供 "Cookies" 的數值。 任何字串值都可以用來區分配置。

應用程式的驗證配置與應用程式的 cookie 驗證配置不同。 當 cookie 驗證配置未提供給 AddCookie 時,它會使用 CookieAuthenticationDefaults.AuthenticationSchemeCookieAuthenticationDefaults.AuthenticationScheme GitHub 來源 會顯示其設為 "Cookies"

驗證 cookie 的 IsEssential 屬性預設會設為 true。 當網站訪客還未同意資料收集時,就允許執行驗證 Cookie。 如需詳細資訊,請參閱 ASP.NET Core 中的一般資料保護規定 (GDPR) 支援

類別 CookieAuthenticationOptions 是用來設定驗證提供者選項。

AddCookie 方法中設定 CookieAuthenticationOptions

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

使用 CookiePolicyOptions 提供給 Cookie 原則中介軟體,即可控制 cookie 處理的全域特性,並在附加或刪除時連結到 cookie 處理的處理常式。

預設 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」 還未被當成配置使用,就請提供設定驗證提供者當初使用的配置。 否則,會使用預設配置。 例如,如果使用「Contoso」作為配置,就請提供設定驗證提供者當初使用的配置。

當關閉瀏覽器時,就會自動刪除工作階段 Cookie (非持續性 Cookie),但關閉單一分頁時,不會清除任何 Cookie。 伺服器不會收到索引標籤或瀏覽器關閉事件的通知。

回應後端變更

一旦建立 cookie,cookie 就成為 identity 的單一來源。 如果後端系統中已停用使用者帳戶:

  • 應用程式的 cookie 驗證系統會根據驗證 cookie 繼續處理要求。
  • 只要驗證 cookie 有效,使用者仍會登入應用程式。

這個 ValidatePrincipal 事件可用來攔截並覆寫 cookieidentity 的驗證。 在每個要求上驗證 cookie,可降低撤銷使用者存取應用程式的風險。

cookie 驗證的其中一種方法,是根據追蹤使用者資料庫的變更時機。 如果自使用者的 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。

AuthenticationProperties 中將 IsPersistent 設為 true

// using Microsoft.AspNetCore.Authentication;

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

您可以使用 ExpiresUtc 來設定絕對到期時間。 若要建立持續性 cookie,IsPersistent 也必須進行設定。 否則,cookie 會以工作階段為基礎的存留期建立,而且可能會在它持有的驗證票證之前或之後到期。 設定 ExpiresUtc 後,它會覆蓋 CookieAuthenticationOptionsExpireTimeSpan 選項的值 (如果已設定)。

下列程式碼片段會建立 identity,然後對應到 cookie,過程將持續 20 分鐘。 這會忽略先前設定的任何滑動到期設定。

// 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 方法中,使用 AddAuthenticationAddCookie 方法來建立驗證中介軟體服務:

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

AuthenticationScheme 傳遞給 AddAuthentication 設定應用程式的預設驗證配置。 當有多個 cookie 驗證執行個體,而且您想要使用特定配置進行授權時,AuthenticationScheme 會很實用。 將 AuthenticationScheme 設定為 CookieAuthenticationDefaults.AuthenticationScheme 會為配置提供 "Cookie" 的數值。 您可以提供可區分配置的任何字串值。

應用程式的驗證配置與應用程式的 cookie 驗證配置不同。 當 cookie 驗證配置未提供給 AddCookie 時,它會使用 CookieAuthenticationDefaults.AuthenticationScheme (「Cookie」)。

驗證 cookie 的 IsEssential 屬性預設會設為 true。 當網站訪客還未同意資料收集時,就允許執行驗證 Cookie。 如需詳細資訊,請參閱 ASP.NET Core 中的一般資料保護規定 (GDPR) 支援

Startup.Configure 中,呼叫 UseAuthenticationUseAuthorization 以設定 HttpContext.User 屬性,並執行要求的授權中介軟體。 呼叫 UseEndpoints 之前先呼叫 UseAuthenticationUseAuthorization 方法:

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

使用 CookiePolicyOptions 提供給 Cookie 原則中介軟體,即可控制 cookie 處理的全域特性,並在附加或刪除時連結到 cookie 處理的處理常式。

預設 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 (或是「Cookie」) 未被當成配置使用 (例如「ContosoCookie」),就請提供設定驗證提供者當初使用的配置。 否則,會使用預設配置。

當關閉瀏覽器時,就會自動刪除工作階段 Cookie (非持續性 Cookie),但關閉單一分頁時,不會清除任何 Cookie。 伺服器不會收到索引標籤或瀏覽器關閉事件的通知。

回應後端變更

一旦建立 cookie,cookie 就成為 identity 的單一來源。 如果後端系統中已停用使用者帳戶:

  • 應用程式的 cookie 驗證系統會根據驗證 cookie 繼續處理要求。
  • 只要驗證 cookie 有效,使用者仍會登入應用程式。

這個 ValidatePrincipal 事件可用來攔截並覆寫 cookieidentity 的驗證。 在每個要求上驗證 cookie,可降低撤銷使用者存取應用程式的風險。

cookie 驗證的其中一種方法,是根據追蹤使用者資料庫的變更時機。 如果自使用者的 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。

AuthenticationProperties 中將 IsPersistent 設為 true

// using Microsoft.AspNetCore.Authentication;

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

您可以使用 ExpiresUtc 來設定絕對到期時間。 若要建立持續性 cookie,IsPersistent 也必須進行設定。 否則,cookie 會以工作階段為基礎的存留期建立,而且可能會在它持有的驗證票證之前或之後到期。 設定 ExpiresUtc 後,它會覆蓋 CookieAuthenticationOptionsExpireTimeSpan 選項的值 (如果已設定)。

下列程式碼片段會建立 identity,然後對應到 cookie,過程將持續 20 分鐘。 這會忽略先前設定的任何滑動到期設定。

// using Microsoft.AspNetCore.Authentication;

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