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 aufIdentity.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.
- In ASP.NET Core-Apps wird PersistKeysToFileSystem verwendet, um den Speicherort des Schlüssels festzulegen.
- In .NET Framework-Apps verwendet die Middleware für Cookie-Authentifizierung eine Implementierung von DataProtectionProvider.
DataProtectionProvider
bietet Datenschutzdienste für die Verschlüsselung und Entschlüsselung der Nutzdaten des Authentifizierungs-cookies. DieDataProtectionProvider
-Instanz ist von dem Datenschutzsystem isoliert, das von anderen Teilen der App verwendet wird. DataProtectionProvider.Create(System.IO.DirectoryInfo, Action<IDataProtectionBuilder>) akzeptiert eine DirectoryInfo zur Angabe des Speicherorts für den Datenschutzschlüssel.
DataProtectionProvider
erfordert das NuGet-Paket Microsoft.AspNetCore.DataProtection.Extensions:- Fügen Sie in .NET Framework-Apps einen Paketverweis auf Microsoft.AspNetCore.DataProtection.Extensions hinzu.
- 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 aufIdentity.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.
- In ASP.NET Core-Apps wird PersistKeysToFileSystem verwendet, um den Speicherort des Schlüssels festzulegen.
- In .NET Framework-Apps verwendet die Middleware für Cookie-Authentifizierung eine Implementierung von DataProtectionProvider.
DataProtectionProvider
bietet Datenschutzdienste für die Verschlüsselung und Entschlüsselung der Nutzdaten des Authentifizierungs-cookies. DieDataProtectionProvider
-Instanz ist von dem Datenschutzsystem isoliert, das von anderen Teilen der App verwendet wird. DataProtectionProvider.Create(System.IO.DirectoryInfo, Action<IDataProtectionBuilder>) akzeptiert eine DirectoryInfo zur Angabe des Speicherorts für den Datenschutzschlüssel.
DataProtectionProvider
erfordert das NuGet-Paket Microsoft.AspNetCore.DataProtection.Extensions:- In ASP.NET Core 2.x-Apps verweisen Sie auf das Microsoft.AspNetCore.App-Metapaket.
- Fügen Sie in .NET Framework-Apps einen Paketverweis auf Microsoft.AspNetCore.DataProtection.Extensions hinzu.
- 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.