Verwenden der cookie-Authentifizierung ohne ASP.NET Core Identity

Von Rick Anderson

ASP.NET Core Identity ist ein umfassender Authentifizierungsanbieter mit vollem Funktionsumfang zum Erstellen und Verwalten von Anmeldungen. Sie können jedoch auch einen cookie-basierten Authentifizierungsanbieter ohne ASP.NET Core Identity verwenden. Weitere Informationen finden Sie unter Einführung in Identity in ASP.NET Core .

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Zu Demonstrationszwecken ist in der Beispiel-App das Benutzerkonto für die hypothetische Benutzerin Maria Rodriguez hartcodiert. Verwenden Sie die E-Mail-Adressemaria.rodriguez@contoso.com und ein beliebiges Kennwort, um die Benutzerin anzumelden. Die Benutzerin wird in der AuthenticateUser-Methode in der Datei Pages/Account/Login.cshtml.cs authentifiziert. In einem realen Beispiel würde die Benutzerin über einen Datenspeicher authentifiziert werden.

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

Durch das Übergeben von AuthenticationScheme an AddAuthentication wird das Standardauthentifizierungsschema für die App festgelegt. AuthenticationScheme ist nützlich, wenn mehrere Instanzen der cookie-Authentifizierung vorhanden sind und die App mit einem bestimmten Schema autorisiert werden muss. Durch Festlegen von AuthenticationScheme auf CookieAuthenticationDefaults.AuthenticationScheme wird der Wert "Cookies" für das Schema bereitgestellt. Es kann ein beliebiger Zeichenfolgenwert verwendet werden, der das Schema eindeutig identifiziert.

Das Authentifizierungsschema der App unterscheidet sich vom cookie-Authentifizierungsschema der App. Wenn kein cookie-Authentifizierungsschema für AddCookie bereitgestellt wurde, wird CookieAuthenticationDefaults.AuthenticationScheme verwendet. Die GitHub-Quelle von CookieAuthenticationDefaults.AuthenticationScheme zeigt, dass "Cookies" als Wert festgelegt ist.

Die IsEssential-Eigenschaft ist bei der cookie-Authentifizierung standardmäßig auf true festgelegt. Ein cookie ist bei der Authentifizierung zulässig, wenn Websitebesucher*innen der Datensammlung nicht zugestimmt haben. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).

Mithilfe der CookieAuthenticationOptions-Klasse werden Optionen des Authentifizierungsanbieters konfiguriert.

Konfigurieren Sie CookieAuthenticationOptions in der AddCookie-Methode:

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

Die Cookie-Richtlinienmiddleware (GitHub-Quelle)UseCookiePolicy aktiviert cookie-Richtlinienfunktionen. Middleware wird in der Reihenfolge verarbeitet, in der sie hinzugefügt wird:

app.UseCookiePolicy(cookiePolicyOptions);

Verwenden Sie die für die Cookie-Richtlinienmiddleware bereitgestellten CookiePolicyOptions, um globale Merkmale der cookie-Verarbeitung zu steuern und cookie-Verarbeitungshandler zu integrieren, wenn ein cookie angefügt oder gelöscht wird.

Der Standardwert von MinimumSameSitePolicy ist SameSiteMode.Lax und erlaubt die OAuth2-Authentifizierung. Legen Sie zum strikten Erzwingen einer Richtlinie für denselben Standort (SameSiteMode.Strict) die MinimumSameSitePolicy fest. Obwohl diese Einstellung OAuth2 und andere ursprungsübergreifende Authentifizierungsschemas außer Kraft setzt, erhöht sie das cookie-Sicherheitsniveau für andere Typen von Apps, die nicht auf der Verarbeitung von ursprungsübergreifenden Anforderungen basieren.

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

Die Einstellung der Cookie-Richtlinienmiddleware für MinimumSameSitePolicy kann sich wie in der folgenden Matrix beschrieben auf die Einstellung von Cookie.SameSite in den CookieAuthenticationOptions-Einstellungen auswirken.

MinimumSameSitePolicy Cookie.SameSite Resultierende Cookie.SameSite-Einstellung
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

Um ein cookie mit den Benutzerinformation zu erstellen, generieren Sie einen ClaimsPrincipal. Die Benutzerinformationen werden serialisiert und im cookie gespeichert.

Erstellen Sie eine ClaimsIdentity mit allen erforderlichen Claims, und rufen Sie SignInAsync auf, um Benutzer*innen anzumelden:

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

Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.

SignInAsync erstellt ein verschlüsseltes cookie und fügt es der aktuellen Antwort hinzu. Wenn AuthenticationScheme nicht angegeben ist, wird das Standardschema verwendet.

RedirectUri wird standardmäßig nur für einige bestimmte Pfade verwendet, z. B. für den Anmeldepfad und die Abmeldepfade. Weitere Informationen finden Sie in der CookieAuthenticationHandler-Quelle.

Für die Verschlüsselung wird das Datenschutzsystem von ASP.NET Core verwendet. Wenn eine App auf mehreren Computern gehostet oder wenn ein App-übergreifender Lastenausgleich oder eine Webfarm verwendet wird, konfigurieren Sie den Datenschutz so, dass derselbe Schlüsselring und App-Bezeichner verwendet wird.

Abmelden

Um aktuelle Benutzer*innen abzumelden und deren cookie zu löschen, rufen Sie SignOutAsync auf:

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

Wenn als Schema nicht CookieAuthenticationDefaults.AuthenticationScheme oder „Cookies“ verwendet wird, geben Sie das Schema beim Konfigurieren des Authentifizierungsanbieters an. Andernfalls wird das Standardschema verwendet. Wenn als Schema z. B. „ContosoCookie“ verwendet wird, geben Sie das Schema beim Konfigurieren des Authentifizierungsanbieters an.

Beim Schließen des Browsers werden sitzungsbasierte cookies (nicht persistente cookies) automatisch gelöscht, es werden aber keine cookies gelöscht, wenn ein einzelner Tab geschlossen wird. Der Server wird nicht über Schließereignisse von Tabs oder Browsern benachrichtigt.

Reagieren auf Back-End-Änderungen

Nachdem ein cookie erstellt wurde, ist das cookie die einzige Identitätsquelle. Wenn ein Benutzerkonto in Back-End-Systemen deaktiviert wird:

  • Das cookie-Authentifizierungssystem der App verarbeitet Anforderungen weiterhin basierend auf dem Authentifizierungs-cookie.
  • Benutzer*innen bleiben so lange bei einer App angemeldet, wie das Authentifizierungs-cookie gültig ist.

Mit dem ValidatePrincipal-Ereignis kann die Überprüfung der cookie-Identität abgefangen und außer Kraft gesetzt werden. Das Überprüfen des cookies bei jeder Anforderung verringert das Risiko, dass gesperrte Benutzer*innen auf die App zugreifen.

Ein Ansatz zur cookie-Validierung basiert darauf nachzuverfolgen, wann sich die Benutzerdatenbank ändert. Wenn die Datenbank seit der Ausstellung von Benutzer-cookies nicht geändert wurde, ist es nicht erforderlich, die Benutzer*innen erneut zu authentifizieren, wenn ihr cookie noch gültig ist. In der Beispiel-App ist die Datenbank in IUserRepository implementiert und speichert einen LastChanged-Wert. Wenn einzelne Benutzer*innen in der Datenbank aktualisiert werden, wird der LastChanged-Wert auf die aktuelle Uhrzeit festgelegt.

Um ein cookie für ungültig zu erklären, wenn sich der LastChanged-Wert in der Datenbank ändert, erstellen Sie mit cookie einem LastChanged-Anspruch, der den aktuellen LastChanged-Wert aus der Datenbank enthält:

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

Um eine Außerkraftsetzung für das ValidatePrincipal-Ereignis zu implementieren, schreiben Sie eine Methode mit der folgenden Signatur in eine Klasse, die von CookieAuthenticationEvents abgeleitet ist:

ValidatePrincipal(CookieValidatePrincipalContext)

Im Folgenden finden Sie eine Beispielimplementierung von 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);
        }
    }
}

Registrieren Sie die Events-Instanz während der cookie-Dienstregistrierung. Stellen Sie eine bereichsbezogene Dienstregistrierung für Ihre CustomCookieAuthenticationEvents-Klasse bereit:

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

Stellen Sie sich eine Situation vor, in der der Name einzelner Benutzer*innen aktualisiert wird – eine Entscheidung, die sich in keiner Weise auf die Sicherheit auswirkt. Wenn Sie den Benutzerprinzipal nicht-destruktiv aktualisieren möchten, rufen Sie context.ReplacePrincipal auf und legen die context.ShouldRenew-Eigenschaft auf true fest.

Warnung

Der hier beschriebene Ansatz wird bei jeder Anforderung ausgelöst. Das Überprüfen von Authentifizierungs-cookies für alle Benutzer*innen bei jeder Anforderung kann zu einer hohen Leistungseinbuße für die App führen.

Persistente cookies

Möglicherweise möchten Sie, dass das cookie über Browsersitzungen hinweg beibehalten wird. Diese Persistenz sollte bei der Anmeldung oder einem ähnlichen Mechanismus nur mit der expliziten Zustimmung der Benutzer*innen über ein Kontrollkästchen wie „Anmeldedaten speichern“ aktiviert werden.

Der folgende Codeschnipsel erstellt eine Identität und ein entsprechendes cookie, das beim Schließen des Browsers erhalten bleibt. Alle zuvor konfigurierten gleitenden Ablaufeinstellungen werden berücksichtigt. Wenn das cookie abläuft, während der Browser geschlossen wird, löscht der Browser das cookie nach dem Neustart.

Legen Sie IsPersistent in true auf AuthenticationProperties fest:

// using Microsoft.AspNetCore.Authentication;

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

Eine absolute Ablaufzeit kann mit ExpiresUtc festgelegt werden. Um ein persistentes cookie zu erstellen, muss IsPersistent ebenfalls festgelegt werden. Andernfalls wird das cookie mit einer sitzungsbasierten Lebensdauer erstellt und kann entweder vor oder nach dem Authentifizierungsticket ablaufen, das es enthält. Wenn ExpiresUtc festgelegt ist, wird der Wert der ExpireTimeSpan-Option von CookieAuthenticationOptions (sofern festgelegt) außer Kraft gesetzt.

Der folgende Codeschnipsel erstellt eine Identität und ein entsprechendes cookie, das 20 Minuten gültig ist. Alle zuvor konfigurierten gleitenden Ablaufeinstellungen werden ignoriert.

// 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 ist ein umfassender Authentifizierungsanbieter mit vollem Funktionsumfang zum Erstellen und Verwalten von Anmeldungen. Sie können jedoch auch einen cookie-basierten Authentifizierungsanbieter ohne ASP.NET Core Identity verwenden. Weitere Informationen finden Sie unter Einführung in Identity in ASP.NET Core .

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Zu Demonstrationszwecken ist in der Beispiel-App das Benutzerkonto für die hypothetische Benutzerin Maria Rodriguez hartcodiert. Verwenden Sie die E-Mail-Adressemaria.rodriguez@contoso.com und ein beliebiges Kennwort, um die Benutzerin anzumelden. Die Benutzerin wird in der AuthenticateUser-Methode in der Datei Pages/Account/Login.cshtml.cs authentifiziert. In einem realen Beispiel würden die Benutzer*innen über einen Datenspeicher authentifiziert werden.

Konfiguration

Erstellen Sie in der Startup.ConfigureServices-Methode die Middlewaredienste für die Authentifizierung mit den Methoden AddAuthentication und AddCookie:

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

Durch das Übergeben von AuthenticationScheme an AddAuthentication wird das Standardauthentifizierungsschema für die App festgelegt. AuthenticationScheme ist nützlich, wenn mehrere Instanzen der cookie-Authentifizierung vorhanden sind und Sie die Autorisierung mit einem bestimmten Schema durchführen möchten. Durch Festlegen von AuthenticationScheme auf CookieAuthenticationDefaults.AuthenticationScheme wird der Wert von „Cookies“ für das Schema bereitgestellt. Sie können einen beliebigen Zeichenfolgenwert angeben, der das Schema eindeutig identifiziert.

Das Authentifizierungsschema der App unterscheidet sich vom cookie-Authentifizierungsschema der App. Wenn kein cookie-Authentifizierungsschema für AddCookie bereitgestellt wurde, wird CookieAuthenticationDefaults.AuthenticationScheme („Cookies“) verwendet.

Die IsEssential-Eigenschaft ist bei der cookie-Authentifizierung standardmäßig auf true festgelegt. Ein cookie ist bei der Authentifizierung zulässig, wenn Websitebesucher*innen der Datensammlung nicht zugestimmt haben. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).

Rufen Sie in Startup.ConfigureUseAuthentication und UseAuthorization auf, um die HttpContext.User-Eigenschaft festzulegen, und führen Sie die Autorisierungsmiddleware für Anforderungen aus. Rufen Sie die Methoden UseAuthentication und UseAuthorization auf, bevor Sie UseEndpoints aufrufen:

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

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

Mithilfe der CookieAuthenticationOptions-Klasse werden Optionen des Authentifizierungsanbieters konfiguriert.

Legen Sie CookieAuthenticationOptions in der Dienstkonfiguration für die Authentifizierung in der Startup.ConfigureServices-Methode fest:

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

Cookie-Richtlinienmiddleware aktiviert cookie-Richtlinienfunktionen. Beim Hinzufügen der Middleware zur App-Verarbeitungspipeline ist die Reihenfolge zu beachten: Sie wirkt sich nur auf Komponenten aus, die in der Pipeline danach registriert werden.

app.UseCookiePolicy(cookiePolicyOptions);

Verwenden Sie die für die Cookie-Richtlinienmiddleware bereitgestellten CookiePolicyOptions, um globale Merkmale der cookie-Verarbeitung zu steuern und cookie-Verarbeitungshandler zu integrieren, wenn ein cookie angefügt oder gelöscht wird.

Der Standardwert von MinimumSameSitePolicy ist SameSiteMode.Lax und erlaubt die OAuth2-Authentifizierung. Legen Sie zum strikten Erzwingen einer Richtlinie für denselben Standort (SameSiteMode.Strict) die MinimumSameSitePolicy fest. Obwohl diese Einstellung OAuth2 und andere ursprungsübergreifende Authentifizierungsschemas außer Kraft setzt, erhöht sie das cookie-Sicherheitsniveau für andere Typen von Apps, die nicht auf der Verarbeitung von ursprungsübergreifenden Anforderungen basieren.

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

Die Einstellung der Cookie-Richtlinienmiddleware für MinimumSameSitePolicy kann sich wie in der folgenden Matrix beschrieben auf die Einstellung von Cookie.SameSite in den CookieAuthenticationOptions-Einstellungen auswirken.

MinimumSameSitePolicy Cookie.SameSite Resultierende Cookie.SameSite-Einstellung
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

Um ein cookie mit den Benutzerinformation zu erstellen, generieren Sie einen ClaimsPrincipal. Die Benutzerinformationen werden serialisiert und im cookie gespeichert.

Erstellen Sie eine ClaimsIdentity mit allen erforderlichen Claims, und rufen Sie SignInAsync auf, um Benutzer*innen anzumelden:

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

Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.

SignInAsync erstellt ein verschlüsseltes cookie und fügt es der aktuellen Antwort hinzu. Wenn AuthenticationScheme nicht angegeben ist, wird das Standardschema verwendet.

RedirectUri wird standardmäßig nur für einige bestimmte Pfade verwendet, z. B. für den Anmeldepfad und die Abmeldepfade. Weitere Informationen finden Sie in der CookieAuthenticationHandler-Quelle.

Für die Verschlüsselung wird das Datenschutzsystem von ASP.NET Core verwendet. Wenn eine App auf mehreren Computern gehostet oder wenn ein App-übergreifender Lastenausgleich oder eine Webfarm verwendet wird, konfigurieren Sie den Datenschutz so, dass derselbe Schlüsselring und App-Bezeichner verwendet wird.

Abmelden

Um aktuelle Benutzer*innen abzumelden und deren cookie zu löschen, rufen Sie SignOutAsync auf:

await HttpContext.SignOutAsync(
    CookieAuthenticationDefaults.AuthenticationScheme);

Wenn als Schema nicht CookieAuthenticationDefaults.AuthenticationScheme oder („Cookies“) verwendet wird (z. B. „ContosoCookie“), geben Sie das Schema beim Konfigurieren des Authentifizierungsanbieters an. Andernfalls wird das Standardschema verwendet.

Beim Schließen des Browsers werden sitzungsbasierte cookies (nicht persistente cookies) automatisch gelöscht, es werden aber keine cookies gelöscht, wenn ein einzelner Tab geschlossen wird. Der Server wird nicht über Schließereignisse von Tabs oder Browsern benachrichtigt.

Reagieren auf Back-End-Änderungen

Nachdem ein cookie erstellt wurde, ist das cookie die einzige Identitätsquelle. Wenn ein Benutzerkonto in Back-End-Systemen deaktiviert wird:

  • Das cookie-Authentifizierungssystem der App verarbeitet Anforderungen weiterhin basierend auf dem Authentifizierungs-cookie.
  • Benutzer*innen bleiben so lange bei einer App angemeldet, wie das Authentifizierungs-cookie gültig ist.

Mit dem ValidatePrincipal-Ereignis kann die Überprüfung der cookie-Identität abgefangen und außer Kraft gesetzt werden. Das Überprüfen des cookies bei jeder Anforderung verringert das Risiko, dass gesperrte Benutzer*innen auf die App zugreifen.

Ein Ansatz zur cookie-Validierung basiert darauf nachzuverfolgen, wann sich die Benutzerdatenbank ändert. Wenn die Datenbank seit der Ausstellung von Benutzer-cookies nicht geändert wurde, ist es nicht erforderlich, die Benutzer*innen erneut zu authentifizieren, wenn ihr cookie noch gültig ist. In der Beispiel-App ist die Datenbank in IUserRepository implementiert und speichert einen LastChanged-Wert. Wenn einzelne Benutzer*innen in der Datenbank aktualisiert werden, wird der LastChanged-Wert auf die aktuelle Uhrzeit festgelegt.

Um ein cookie für ungültig zu erklären, wenn sich der LastChanged-Wert in der Datenbank ändert, erstellen Sie mit cookie einem LastChanged-Anspruch, der den aktuellen LastChanged-Wert aus der Datenbank enthält:

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

Um eine Außerkraftsetzung für das ValidatePrincipal-Ereignis zu implementieren, schreiben Sie eine Methode mit der folgenden Signatur in eine Klasse, die von CookieAuthenticationEvents abgeleitet ist:

ValidatePrincipal(CookieValidatePrincipalContext)

Im Folgenden finden Sie eine Beispielimplementierung von 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);
        }
    }
}

Registrieren Sie die Events-Instanz während der cookie-Dienstregistrierung in der Startup.ConfigureServices-Methode. Stellen Sie eine bereichsbezogene Dienstregistrierung für Ihre CustomCookieAuthenticationEvents-Klasse bereit:

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

services.AddScoped<CustomCookieAuthenticationEvents>();

Stellen Sie sich eine Situation vor, in der der Name einzelner Benutzer*innen aktualisiert wird – eine Entscheidung, die sich in keiner Weise auf die Sicherheit auswirkt. Wenn Sie den Benutzerprinzipal nicht-destruktiv aktualisieren möchten, rufen Sie context.ReplacePrincipal auf und legen die context.ShouldRenew-Eigenschaft auf true fest.

Warnung

Der hier beschriebene Ansatz wird bei jeder Anforderung ausgelöst. Das Überprüfen von Authentifizierungs-cookies für alle Benutzer*innen bei jeder Anforderung kann zu einer hohen Leistungseinbuße für die App führen.

Persistente cookies

Möglicherweise möchten Sie, dass das cookie über Browsersitzungen hinweg beibehalten wird. Diese Persistenz sollte bei der Anmeldung oder einem ähnlichen Mechanismus nur mit der expliziten Zustimmung der Benutzer*innen über ein Kontrollkästchen wie „Anmeldedaten speichern“ aktiviert werden.

Der folgende Codeschnipsel erstellt eine Identität und ein entsprechendes cookie, das beim Schließen des Browsers erhalten bleibt. Alle zuvor konfigurierten gleitenden Ablaufeinstellungen werden berücksichtigt. Wenn das cookie abläuft, während der Browser geschlossen wird, löscht der Browser das cookie nach dem Neustart.

Legen Sie IsPersistent in true auf AuthenticationProperties fest:

// using Microsoft.AspNetCore.Authentication;

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

Eine absolute Ablaufzeit kann mit ExpiresUtc festgelegt werden. Um ein persistentes cookie zu erstellen, muss IsPersistent ebenfalls festgelegt werden. Andernfalls wird das cookie mit einer sitzungsbasierten Lebensdauer erstellt und kann entweder vor oder nach dem Authentifizierungsticket ablaufen, das es enthält. Wenn ExpiresUtc festgelegt ist, wird der Wert der ExpireTimeSpan-Option von CookieAuthenticationOptions (sofern festgelegt) außer Kraft gesetzt.

Der folgende Codeschnipsel erstellt eine Identität und ein entsprechendes cookie, das 20 Minuten gültig ist. Alle zuvor konfigurierten gleitenden Ablaufeinstellungen werden ignoriert.

// using Microsoft.AspNetCore.Authentication;

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