Freigeben von Authentifizierungs-cookies zwischen ASP.NET-Apps

Von Rick Anderson

Websites bestehen oft aus einzelnen Web-Apps, die zusammenarbeiten. Um eine Umgebung mit einmaligem Anmelden (Single Sign-On, SSO) zu ermöglichen, müssen Web-Apps innerhalb einer Website die Authentifizierungs-cookies gemeinsam nutzen. Um dieses Szenario zu unterstützen, ermöglicht der Datenschutzstapel die gemeinsame Nutzung von Katana-cookie-Authentifizierung und ASP.NET Core-cookie-Authentifizierungstickets.

In den folgenden Beispielen:

  • Der Name des Authentifizierungs-cookies wird auf einen gemeinsamen Wert von .AspNet.SharedCookie festgelegt.
  • Der AuthenticationType wird entweder explizit oder standardmäßig auf Identity.Application festgelegt.
  • Ein gemeinsamer App-Name, SharedCookieApp, wird verwendet, damit das Datenschutzsystem entsprechende Datenschutzschlüssel gemeinsam nutzen kann.
  • Identity.Application wird als Authentifizierungsschema verwendet. Welches Schema auch immer verwendet wird, es muss innerhalb und über die freigegebenen cookie-Apps hinweg konsistent verwendet werden, entweder als Standardschema oder indem es explizit festgelegt wird. Das Schema wird beim Verschlüsseln und Entschlüsseln von cookies verwendet, sodass ein konsistentes Schema für alle Apps verwendet werden muss.
  • Es wird ein gemeinsamer Datenschutzschlüssel für den Speicherort verwendet.
  • DataProtectionProvider erfordert das NuGet-Paket Microsoft.AspNetCore.DataProtection.Extensions:
  • SetApplicationName legt den gemeinsamen Namen der App fest.

Freigeben von Authentifizierungs-cookies mit ASP.NET Core Identity

Beim Verwenden von ASP.NET Core Identity:

  • Die Datenschutzschlüssel und der Name der App müssen von den Apps gemeinsam genutzt werden. In den folgenden Beispielen wird ein gemeinsamer Schlüsselspeicherort für die PersistKeysToFileSystem-Methode bereitgestellt. Verwenden Sie SetApplicationName, um einen gemeinsamen freigegebenen App-Namen zu konfigurieren (SharedCookieApp in den folgenden Beispielen). Weitere Informationen finden Sie unter Konfigurieren des Schutzes von Daten in ASP.NET Core.
  • Verwenden Sie die ConfigureApplicationCookie-Erweiterungsmethode, um den Dienst zum Schutz der Daten für cookies einzurichten.
  • Der Standardauthentifizierungstyp ist Identity.Application.

In Program.cs:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

var app = builder.Build();

Hinweis: Die vorangehenden Anweisungen funktionieren nicht mit ITicketStore (CookieAuthenticationOptions.SessionStore). Weitere Informationen finden Sie in diesem GitHub-Issue.

Aus Sicherheitsgründen sind Authentifizierungscookies (cookies) nicht in ASP.NET Core komprimiert. Wenn Sie cookies zur Authentifizierung verwenden, sollten Entwickler die Anzahl von enthaltenen Anspruchsinformationen möglichst gering halten.

Freigeben von Authentifizierungs-cookies ohne ASP.NET Core Identity

Wenn Sie cookies direkt ohne ASP.NET Core Identity verwenden, konfigurieren Sie Datenschutz und Authentifizierung. Im folgenden Beispiel wird der Authentifizierungstyp auf Identity.Application festgelegt:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

var app = builder.Build();

Aus Sicherheitsgründen sind Authentifizierungscookies (cookies) nicht in ASP.NET Core komprimiert. Wenn Sie cookies zur Authentifizierung verwenden, sollten Entwickler die Anzahl von enthaltenen Anspruchsinformationen möglichst gering halten.

Freigeben von cookies über verschiedene Basispfade

Ein Authentifizierungs-cookie verwendet HttpRequest.PathBase als standardmäßiges Cookie.Path. Wenn das cookie der App über verschiedene Basispfade freigegeben werden muss, muss Path außer Kraft gesetzt werden:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

var app = builder.Build();

Unterdomänenübergreifende Freigabe von cookies

Wenn Sie Apps hosten, die cookies unterdomänenübergreifend freigeben, geben Sie eine gemeinsame Domäne in der Cookie.Domain-Eigenschaft an. Um cookies App-übergreifend bei contoso.com freizugeben, z. B. first_subdomain.contoso.com und second_subdomain.contoso.com, geben Sie die Cookie.Domain als .contoso.com an:

options.Cookie.Domain = ".contoso.com";

Verschlüsseln ruhender Datenschutzschlüssel

Für die Bereitstellung in der Produktion konfigurieren Sie den DataProtectionProvider, um die ruhenden Schlüssel mit DPAPI oder einem X509-Zertifikat zu verschlüsseln. Weitere Informationen finden Sie unter Verschlüsselung ruhender Daten mit Schlüsseln in Windows und Azure mithilfe von ASP.NET Core. Im folgenden Beispiel wird ein Zertifikatfingerabdruck für ProtectKeysWithCertificate bereitgestellt:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

Verwenden einer gemeinsamen Benutzerdatenbank

Wenn Apps dasselbe Identity-Schema verwenden (dieselbe Version von Identity), stellen Sie sicher, dass das Identity-System für jede App auf dieselbe Benutzerdatenbank verweist. Andernfalls produziert das Identitätssystem zur Laufzeit Fehler, wenn es versucht, die Informationen im Authentifizierungs-cookie mit den Informationen in seiner Datenbank abzugleichen.

Wenn das Identity-Schema zwischen den Apps unterschiedlich ist, in der Regel weil die Apps unterschiedliche Identity-Versionen verwenden, ist die gemeinsame Nutzung einer Datenbank auf der Grundlage der neuesten Version von Identity nicht möglich, ohne dass Sie Spalten in den Identity-Schemas der anderen Apps neu zuordnen und hinzufügen müssen. Oft ist es effizienter, für die anderen Apps ein Upgrade auf die neueste Identity-Version durchzuführen, sodass eine gemeinsame Datenbank für die Apps freigegeben werden kann.

Änderung des Anwendungsnamens

In .NET 6 normalisiert WebApplicationBuilder den Inhaltsstammpfad so, dass er mit DirectorySeparatorChar endet. Die meisten Apps, die von HostBuilder oder WebHostBuilder migriert werden, haben nicht denselben App-Namen, da sie nicht normalisiert sind. Weitere Informationen finden Sie unter SetApplicationName.

Freigeben von Authentifizierungs-cookies zwischen ASP.NET 4.x und ASP.NET Core-Apps

ASP.NET 4.x-Apps, die Microsoft.Owin-Middleware für Cookie-Authentifizierung verwenden, können so konfiguriert werden, dass sie cookie-Authentifizierungen generieren, die mit der ASP.NET Core-Middleware für Cookie-Authentifizierung kompatibel sind. Dies kann nützlich sein, wenn eine Webanwendung sowohl aus ASP.NET 4.x-Apps als auch aus ASP.NET Core-Apps besteht, die eine gemeinsame Oberfläche für einmaliges Anmelden benötigen. Ein konkretes Beispiel für ein solches Szenario ist die inkrementelle Migration einer Web-App von ASP.NET zu ASP.NET Core. In solchen Szenarien ist es üblich, dass einige Teile einer App von der ursprünglichen ASP.NET-App versorgt werden, während andere von der neuen ASP.NET Core-App versorgt werden. Die Benutzer sollten sich jedoch nur einmalig anmelden müssen. Dies kann durch einen der folgenden Ansätze erreicht werden:

  • Verwendung des Features Remoteauthentifizierung des System.Web-Adapters, das die ASP.NET-App zur Anmeldung von Benutzern verwendet.
  • Konfigurieren der ASP.NET-App zur Verwendung der Microsoft.Owin-Middleware für Cookie-Authentifizierung, damit Authentifizierungs-cookies mit der ASP.NET Core-App freigegeben werden.

Um die ASP.NET Microsoft.Owin-Middleware für Cookie-Authentifizierung für die gemeinsame Nutzung von cookies mit einer ASP.NET Core-App zu konfigurieren, befolgen Sie die vorangehenden Anweisungen, um die ASP.NET Core-App so zu konfigurieren, dass sie einen bestimmten cookie-Namen und App-Namen verwendet und die Datenschutzschlüssel an einem bekannten Ort aufbewahrt. Weitere Informationen zur Persistenz von Datenschutzschlüsseln finden Sie unter Konfigurieren des Schutzes von Daten in ASP.NET Core.

Installieren Sie in der ASP.NET-App das Paket Microsoft.Owin.Security.Interop.

Aktualisieren Sie den UseCookieAuthentication-Aufruf in Startup.Auth.cs, um ein AspNetTicketDataFormat festzulegen, das den Einstellungen der ASP.NET Core-App entspricht:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    { 
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },

    // Settings to configure shared cookie with ASP.NET Core app
    CookieName = ".AspNet.ApplicationCookie",
    AuthenticationType = "Identity.Application",                
    TicketDataFormat = new AspNetTicketDataFormat(
        new DataProtectorShim(
            DataProtectionProvider.Create(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"),
            builder => builder.SetApplicationName("SharedCookieApp"))
            .CreateProtector(
                "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
                // Must match the Scheme name used in the ASP.NET Core app, i.e. IdentityConstants.ApplicationScheme
                "Identity.Application",
                "v2"))),
    CookieManager = new ChunkingCookieManager()
});

Wichtige Elemente, die hier konfiguriert werden, sind:

  • Der cookie-Name ist auf denselben Namen wie in der ASP.NET Core-App festgelegt.
  • Ein Anbieter für den Datenschutz wird mithilfe desselben Schlüsselringpfads erstellt. Beachten Sie, dass in diesen Beispielen die Datenschutzschlüssel auf Datenträgern gespeichert sind, aber auch andere Anbieter für den Schutz von Daten verwendet werden können. Beispielsweise können Redis oder Azure Blob Storage als Anbieter für den Schutz von Daten verwendet werden, solange die Konfiguration zwischen den Apps übereinstimmt. Weitere Informationen zur Persistenz von Datenschutzschlüsseln finden Sie unter Konfigurieren des Schutzes von Daten in ASP.NET Core.
  • Der App-Name wird so festgelegt, dass er mit dem in der ASP.NET Core-App verwendeten App-Namen übereinstimmt.
  • Der Authentifizierungstyp wird auf den Namen des Authentifizierungsschemas in der ASP.NET Core-App festgelegt.
  • System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier wird auf einen Anspruch aus der ASP.NET Core-Identität festgelegt, der für einen Benutzer eindeutig ist.

Da der Authentifizierungstyp geändert wurde, um dem Authentifizierungsschema der ASP.NET Core-App zu entsprechen, muss auch die Art und Weise, wie die ASP.NET-App neue Identitäten generiert, aktualisiert werden, um denselben Namen zu verwenden. Dies erfolgt normalerweise in Models/IdentityModels.cs:

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, "Identity.Application");
        
        // Add custom user claims here
        return userIdentity;
    }
}

Mit diesen Änderungen können die ASP.NET- und ASP.NET Core-Apps dieselbe Authentifizierungs-cookies verwenden, sodass Benutzer, die sich in einer App an- oder abmelden, auch in der anderen App angezeigt werden.

Beachten Sie, dass es Unterschiede zwischen den Datenbankschemata von ASP.NET Identity und ASP.NET Core Identity gibt. Es wird daher empfohlen, dass Benutzer sich nur über eine der Apps anmelden – entweder über die ASP.NET- oder die ASP.NET Core-App. Sobald die Benutzer angemeldet sind, ermöglichen die in diesem Abschnitt dokumentierten Schritte, dass das Authentifizierungs-cookie von beiden Apps verwendet wird und beide Apps in der Lage sein sollten, Benutzer abzumelden.

Zusätzliche Ressourcen

In den folgenden Beispielen:

  • Der Name des Authentifizierungs-cookies wird auf einen gemeinsamen Wert von .AspNet.SharedCookie festgelegt.
  • Der AuthenticationType wird entweder explizit oder standardmäßig auf Identity.Application festgelegt.
  • Ein gemeinsamer App-Name wird verwendet, damit das Datenschutzsystem entsprechende Datenschutzschlüssel (SharedCookieApp) gemeinsam nutzen kann.
  • Identity.Application wird als Authentifizierungsschema verwendet. Welches Schema auch immer verwendet wird, es muss innerhalb und über die freigegebenen cookie-Apps hinweg konsistent verwendet werden, entweder als Standardschema oder indem es explizit festgelegt wird. Das Schema wird beim Verschlüsseln und Entschlüsseln von cookies verwendet, sodass ein konsistentes Schema für alle Apps verwendet werden muss.
  • Es wird ein gemeinsamer Datenschutzschlüssel für den Speicherort verwendet.
  • DataProtectionProvider erfordert das NuGet-Paket Microsoft.AspNetCore.DataProtection.Extensions:
  • SetApplicationName legt den gemeinsamen Namen der App fest.

Freigeben von Authentifizierungs-cookies mit ASP.NET Core Identity

Beim Verwenden von ASP.NET Core Identity:

  • Die Datenschutzschlüssel und der Name der App müssen von den Apps gemeinsam genutzt werden. In den folgenden Beispielen wird ein gemeinsamer Schlüsselspeicherort für die PersistKeysToFileSystem-Methode bereitgestellt. Verwenden Sie SetApplicationName, um einen gemeinsamen freigegebenen App-Namen zu konfigurieren (SharedCookieApp in den folgenden Beispielen). Weitere Informationen finden Sie unter Konfigurieren des Schutzes von Daten in ASP.NET Core.
  • Verwenden Sie die ConfigureApplicationCookie-Erweiterungsmethode, um den Dienst zum Schutz der Daten für cookies einzurichten.
  • Der Standardauthentifizierungstyp ist Identity.Application.

In Startup.ConfigureServices:

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

Hinweis: Die vorangehenden Anweisungen funktionieren nicht mit ITicketStore (CookieAuthenticationOptions.SessionStore). Weitere Informationen finden Sie in diesem GitHub-Issue.

Aus Sicherheitsgründen sind Authentifizierungscookies (cookies) nicht in ASP.NET Core komprimiert. Wenn Sie cookies zur Authentifizierung verwenden, sollten Entwickler die Anzahl von enthaltenen Anspruchsinformationen möglichst gering halten.

Freigeben von Authentifizierungs-cookies ohne ASP.NET Core Identity

Wenn Sie cookies direkt ohne ASP.NET Core Identity verwenden, konfigurieren Sie Datenschutz und Authentifizierung in Startup.ConfigureServices. Im folgenden Beispiel wird der Authentifizierungstyp auf Identity.Application festgelegt:

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

Aus Sicherheitsgründen sind Authentifizierungscookies (cookies) nicht in ASP.NET Core komprimiert. Wenn Sie cookies zur Authentifizierung verwenden, sollten Entwickler die Anzahl von enthaltenen Anspruchsinformationen möglichst gering halten.

Freigeben von cookies über verschiedene Basispfade

Ein Authentifizierungs-cookie verwendet HttpRequest.PathBase als standardmäßiges Cookie.Path. Wenn das cookie der App über verschiedene Basispfade freigegeben werden muss, muss Path außer Kraft gesetzt werden:

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

Unterdomänenübergreifende Freigabe von cookies

Wenn Sie Apps hosten, die cookies unterdomänenübergreifend freigeben, geben Sie eine gemeinsame Domäne in der Cookie.Domain-Eigenschaft an. Um cookies App-übergreifend bei contoso.com freizugeben, z. B. first_subdomain.contoso.com und second_subdomain.contoso.com, geben Sie die Cookie.Domain als .contoso.com an:

options.Cookie.Domain = ".contoso.com";

Verschlüsseln ruhender Datenschutzschlüssel

Für die Bereitstellung in der Produktion konfigurieren Sie den DataProtectionProvider, um die ruhenden Schlüssel mit DPAPI oder einem X509-Zertifikat zu verschlüsseln. Weitere Informationen finden Sie unter Verschlüsselung ruhender Daten mit Schlüsseln in Windows und Azure mithilfe von ASP.NET Core. Im folgenden Beispiel wird ein Zertifikatfingerabdruck für ProtectKeysWithCertificate bereitgestellt:

services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

Freigeben von Authentifizierungs-cookies zwischen ASP.NET 4.x und ASP.NET Core-Apps

ASP.NET 4.x-Apps, die Katana-Middleware für Cookie-Authentifizierung verwenden, können so konfiguriert werden, dass sie cookie-Authentifizierungen generieren, die mit der ASP.NET Core-Middleware für Cookie-Authentifizierung kompatibel sind. Weitere Informationen finden Sie unter Freigeben von Authentifizierungs-cookies zwischen ASP.NET 4.x und ASP.NET Core-Apps (dotnet/AspNetCore.Docs #21987).

Verwenden einer gemeinsamen Benutzerdatenbank

Wenn Apps dasselbe Identity-Schema verwenden (dieselbe Version von Identity), stellen Sie sicher, dass das Identity-System für jede App auf dieselbe Benutzerdatenbank verweist. Andernfalls produziert das Identitätssystem zur Laufzeit Fehler, wenn es versucht, die Informationen im Authentifizierungs-cookie mit den Informationen in seiner Datenbank abzugleichen.

Wenn das Identity-Schema zwischen den Apps unterschiedlich ist, in der Regel weil die Apps unterschiedliche Identity-Versionen verwenden, ist die gemeinsame Nutzung einer Datenbank auf der Grundlage der neuesten Version von Identity nicht möglich, ohne dass Sie Spalten in den Identity-Schemas der anderen Apps neu zuordnen und hinzufügen müssen. Oft ist es effizienter, für die anderen Apps ein Upgrade auf die neueste Identity-Version durchzuführen, sodass eine gemeinsame Datenbank für die Apps freigegeben werden kann.

Zusätzliche Ressourcen