Teilen über


Sichern eines ASP.NET Core Blazor Web App mit OpenID Connect (OIDC)

Dieser Artikel beschreibt, wie man eine Blazor Web App mit OpenID Connect (OIDC) anhand einer Beispiel-App im dotnet/blazor-samples GitHub-Repository (.NET 8 oder höher) sichert (Hinweis zum Download).

Diese Version des Artikels behandelt die Implementierung von OIDC, ohne dass das BFF-Muster (Back-End für Front-Ends) dafür übernommen wird. Das BFF-Muster ist nützlich, um authentifizierte Anforderungen an externe Dienste zu senden. Ändern Sie die Artikelversionsauswahl in OIDC mit BFF-Muster, wenn die Spezifikation der App das BFF-Muster vorsieht.

Die folgende Spezifikation wird behandelt:

  • Die Blazor Web App verwendet den automatischen Rendermodus mit globaler Interaktivität.
  • Benutzerdefinierte Dienste für Authentifizierungsstatusanbieter werden von Server- und Client-Apps verwendet, um den Authentifizierungsstatus von Benutzern bzw. Benutzerinnen zu erfassen und zwischen Server und Client zu übertragen.
  • Diese App ist ein Ausgangspunkt für jeden OIDC-Authentifizierungsflow. OIDC wird manuell in der App konfiguriert und ist nicht auf Microsoft Entra ID oder Microsoft Identity Web-Pakete angewiesen, und die Beispiel-App erfordert kein Microsoft Azure-Hosting. Die Beispiel-App kann jedoch mit Entra und Microsoft Identity Web verwendet und in Azure gehostet werden.
  • Automatische nicht interaktive Tokenaktualisierung
  • Ruft eine (Web)-API sicher im Serverprojekt für Daten auf.

Beispiel-App

Die Beispiel-App umfasst zwei Projekte:

  • BlazorWebAppOidc: Serverseitiges Projekt des Blazor Web App, das einen Beispiel Minimal API-Endpunkt für Wetterdaten enthält.
  • BlazorWebAppOidc.Client: Client-seitiges Projekt der Blazor Web App.

Sie können über den Repositorystamm über folgenden Link auf die Beispiel-Apps im neuesten Versionsordner zugreifen. Die Projekte für .NET 8 oder höher befinden sich im Ordner BlazorWebAppOidc.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Server-seitiges Blazor Web App-Projekt (BlazorWebAppOidc)

Das BlazorWebAppOidc-Projekt ist das serverseitige Projekt des Blazor Web App.

Die Datei BlazorWebAppOidc.http kann zum Testen der Wetterdatenanforderung verwendet werden. Beachten Sie, dass das BlazorWebAppOidc-Projekt ausgeführt werden muss, um den Endpunkt zu testen, wobei der Endpunkt in der Datei hartcodiert ist. Weitere Informationen finden Sie unter Verwenden von HTTP-Dateien in Visual Studio 2022.

Hinweis

Das Serverprojekt verwendet IHttpContextAccessor/HttpContext, jedoch nie für interaktiv gerenderte Komponenten. Weitere Informationen finden Sie im Leitfaden zur Bedrohungsabwehr für das interaktive serverseitige Rendering von ASP.NET Core Blazor.

Konfiguration

In diesem Abschnitt wird erläutert, wie Sie die Beispiel-App konfigurieren.

Hinweis

Für Microsoft Entra ID und Azure AD B2C können Sie AddMicrosoftIdentityWebApp aus Microsoft Identity Web (NuGet-Paket Microsoft.Identity.Web, API-Dokumentation) verwenden. Damit werden der OIDC- und der Cookie-Authentifizierungshandler mit den entsprechenden Standardwerten hinzugefügt. Die Beispiel-App und die Anleitung in diesem Abschnitt verwenden nicht Microsoft Identity Web. Die Anleitung veranschaulicht, wie der OIDC-Handler manuell für die einzelnen OIDC-Anbieter konfiguriert wird. Weitere Informationen zur Implementierung von Microsoft Identity Web finden Sie in den verknüpften Ressourcen.

Die folgende OpenIdConnectOptions-Konfiguration befindet sich in der Datei Program des Projekts beim Aufruf von AddOpenIdConnect:

  • SignInScheme: Legt das Authentifizierungsschema fest, das der Middleware entspricht, die für die Speicherung der Benutzerdaten identity nach einer erfolgreichen Authentifizierung verantwortlich ist. Der OIDC-Handler muss ein Anmeldeschema verwenden, das Benutzeranmeldeinformationen über Anforderungen hinweg beibehalten kann. Die folgende Zeile dient ist lediglich der Veranschaulichung. Wird sie weggelassen, wird DefaultSignInScheme als Fallbackwert verwendet.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Bereiche für openid und profile (Scope) (Optional): Die Bereiche openid und profile werden ebenfalls standardmäßig konfiguriert, da Sie erforderlich sind, damit der OIDC-Handler funktioniert. Sie müssen jedoch möglicherweise erneut hinzugefügt werden, wenn Bereiche in der Authentication:Schemes:MicrosoftOidc:Scope-Konfiguration enthalten sind. Allgemeine Anleitungen zur Konfiguration finden Sie unter Konfiguration in ASP.NET Core und ASP.NET Core-Blazor-Konfiguration.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: Definiert, ob Zugriffs- und Aktualisierungstoken nach einer erfolgreichen Autorisierung in AuthenticationProperties gespeichert werden sollen. Diese Eigenschaft ist auf false festgelegt, um die Größe des endgültigen cookie-Elements für die Authentifizierung zu verringern.

    oidcOptions.SaveTokens = false;
    
  • Bereich für den Offlinezugriff (Scope): Der Bereich offline_access ist für das Aktualisierungstoken erforderlich.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Authority und ClientId: Legt die Autoritäts- und Client-ID für OIDC-Aufrufe fest.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Beispiel:

    • Autorität ({AUTHORITY}): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (verwendet Mandanten-ID a3942615-d115-4eb7-bc84-9974abcf5064)
    • Client-ID ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Beispiel für die Autorität „common“ von Microsoft Azure:

    Die Autorität „common“ sollte für mehrinstanzenfähige Apps verwendet werden. Sie können die Autorität „common“ auch für einzelinstanzenfähige Apps verwenden, allerdings ist ein benutzerdefinierter IssuerValidator-Wert erforderlich, wie weiter unten in diesem Abschnitt gezeigt.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret: Der geheimer OIDC-Clientschlüssel

    Das folgende Beispiel dient nur zu Test- und Demonstrationszwecken. Speichern Sie den geheimen Clientschlüssel nicht in der Assembly der App, und checken Sie den geheimen Schlüssel nicht in die Quellcodeverwaltung ein. Speichern Sie den geheimen Clientschlüssel unter Benutzergeheimnisse, in Azure Key Vault oder in einer Umgebungsvariablen.

    Die Konfiguration des Authentifizierungsschemas wird automatisch aus builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"] gelesen, wobei der {SCHEME NAME}-Platzhalter das Schema ist, das MicrosoftOidc ist. Da die Konfiguration vorkonfiguriert ist, kann ein geheimer Clientschlüssel automatisch über den Konfigurationsschlüssel Authentication:Schemes:MicrosoftOidc:ClientSecret gelesen werden. Benennen Sie auf dem Server mithilfe von Umgebungsvariablen die Umgebungsvariable Authentication__Schemes__MicrosoftOidc__ClientSecret:

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    Nur zu Demonstrations- und Testzwecken. ClientSecret kann direkt festgelegt werden. Legen Sie den Wert nicht direkt für bereitgestellte Produktions-Apps fest. Für etwas mehr Sicherheit müssen Sie die Zeile bedingt mit dem Symbol DEBUG kompilieren:

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    Beispiel:

    Geheimer Clientschlüssel ({CLIENT SECRET}): 463471c8c4...f90d674bc9 (für die Darstellung gekürzt)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType: Konfiguriert den OIDC-Handler so, dass nur der Autorisierungscodeflow ausgeführt wird. Implizite Genehmigungen und Hybridflows sind in diesem Modus nicht erforderlich.

    Aktivieren Sie in der App-Registrierungskonfiguration Implizite Genehmigung und Hybridflows im Entra- oder Azure-Portal *keins der Kontrollkästchen für den Autorisierungsendpunkt, um Zugriffstoken oder ID-Token zurückzugeben. Der OIDC-Handler fordert automatisch die entsprechenden Token mithilfe des vom Autorisierungsendpunkt zurückgegebenen Codes an.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaims und die Konfiguration von NameClaimType und RoleClaimType: Viele OIDC-Server verwenden name und role anstelle der Standardwerte für SOAP/WS-Fed in ClaimTypes. Wenn MapInboundClaims auf false festgelegt ist, führt der Handler keine Anspruchszuordnungen durch und die Anspruchsnamen aus dem JWT werden direkt von der App verwendet. Im folgenden Beispiel wird der Rollenanspruchstyp auf roles festgelegt, wie für die Microsoft Entra-ID (ME-ID) passend. Weitere Informationen finden Sie in der Dokumentation Ihres identity Anbieters.

Hinweis

MapInboundClaims muss für die meisten OIDC-Anbieter auf false festgelegt werden, um das Umbenennen von Ansprüchen zu verhindern.

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
  • Pfadkonfiguration: Die Pfade müssen mit den bei der Registrierung der Anwendung beim OIDC-Anbieter konfigurierten Pfaden für den Umleitungs-URI (Anmelderückrufpfad) und für die Umleitung nach der Abmeldung (abgemeldeter Rückrufpfad) übereinstimmen. Im Azure-Portal werden Pfade auf dem Blatt Authentifizierung der App-Registrierung konfiguriert. Sowohl die Anmelde- als auch die Abmeldepfade müssen als Umleitungs-URIs registriert werden. Die Standardwerte sind /signin-oidc und /signout-callback-oidc.

    • CallbackPath: Der Anforderungspfad im Basispfad der Anwendung, an den der Benutzer-Agent zurückgegeben wird

      Legen Sie im Entra- oder Azure-Portal den Pfad im Umleitungs-URI der Plattformkonfiguration für Web fest:

      https://localhost/signin-oidc

      Hinweis

      Bei Verwendung von Microsoft Entra ID ist für localhost kein Port erforderlich. Die meisten anderen OIDC-Anbieter erfordern einen richtigen Port.

    • SignedOutCallbackPath: Der Anforderungspfad innerhalb des Basispfads der Anwendung, an den der Benutzeragent nach der Abmeldung vom identity-Anbieter zurückgegeben wird.

      Legen Sie im Entra- oder Azure-Portal den Pfad im Umleitungs-URI der Plattformkonfiguration für Web fest:

      https://localhost/signout-callback-oidc

      Hinweis

      Bei Verwendung von Microsoft Entra ID ist für localhost kein Port erforderlich. Die meisten anderen OIDC-Anbieter erfordern einen richtigen Port.

      Hinweis

      Bei Verwendung von Microsoft Identity Web leitet der Anbieter derzeit nur zurück an SignedOutCallbackPath um, wenn microsoftonline.com die Autorität (https://login.microsoftonline.com/{TENANT ID}/v2.0/) verwendet wird. Diese Einschränkung besteht nicht, wenn Sie die Autorität „common“ mit Microsoft Identity Web verwenden können. Weitere Informationen finden Sie unter postLogoutRedirectUri funktioniert nicht, wenn die Autoritäts-URL eine Mandanten-ID enthält (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: Unter diesem Pfad empfangene Anforderungen führen dazu, dass der Handler die Abmeldung mithilfe des Abmeldeschemas aufruft.

      Legen Sie im Entra- oder Azure-Portal die URL für Front-Channel-Abmeldung fest:

      https://localhost/signout-oidc

      Hinweis

      Bei Verwendung von Microsoft Entra ID ist für localhost kein Port erforderlich. Die meisten anderen OIDC-Anbieter erfordern einen richtigen Port.

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    Beispiele (Standardwerte):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure nur mit dem Endpunkt „common“) TokenValidationParameters.IssuerValidator: Viele OIDC-Anbieter arbeiten mit dem Standardaussteller-Validierungssteuerelement, wir müssen jedoch den Aussteller berücksichtigen, der mit der von https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration zurückgegebenen Mandanten-ID ({TENANT ID}) parametrisiert ist. Weitere Informationen finden Sie unter SecurityTokenInvalidIssuerException bei OpenID Connect und beim Azure AD-Endpunkt „common“ (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731).

    Nur für Apps, die Microsoft Entra ID oder Azure AD B2C mit dem Endpunkt „common“ verwenden:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Code der Beispiel-App

Sehen Sie sich die folgenden Features der Beispiel-App an:

  • Automatische, nicht interaktive Tokenaktualisierung mithilfe einer benutzerdefinierten cookie-Aktualisierung (CookieOidcRefresher.cs)
  • Die Klasse PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) ist ein serverseitiges AuthenticationStateProvider-Element, das PersistentComponentState verwendet, um den Authentifizierungsstatus an den Client zu senden, der dann für die Lebensdauer der WebAssembly-Anwendung festgelegt wird.
  • Eine Beispielanforderung an die Blazor Web App für Wetterdaten wird von einem Minimal-API-Endpunkt (/weather-forecast) in der Program-Datei (Program.cs) bearbeitet. Für den Endpunkt ist eine Autorisierung durch Aufruf von RequireAuthorizationerforderlich. Fügen Sie für alle Controller, die Sie dem Projekt hinzufügen, das [Authorize]-Attribut dem Controller oder der Aktion hinzu.
  • Die App ruft eine (Web)-API im Serverprojekt sicher für Wetterdaten auf:
    • Beim Rendern der Weather Komponente auf dem Server verwendet die Komponente den ServerWeatherForecaster server, um Wetterdaten direkt abzurufen (nicht über einen Web-API-Aufruf).
    • Wenn die Komponente auf dem Client gerendert wird, verwendet die Komponente die ClientWeatherForecaster Dienstimplementierung, die eine vorkonfigurierte HttpClient (in der Datei des Clientprojekts Program ) verwendet, um einen Web-API-Aufruf an das Serverprojekt durchzuführen. Ein minimaler API-Endpunkt (/weather-forecast), der in der Datei des Serverprojekts Program definiert ist, ruft die Wetterdaten aus dem ServerWeatherForecaster Und gibt die Daten an den Client zurück.

Weitere Informationen zu (Web-)API-Aufrufen unter Verwendung von Dienstabstraktionen in Blazor Web Apps finden Sie unter Aufruf einer Web-API von einer ASP.NET Core-Blazor-App.

Client-seitiges Blazor Web App Projekt (BlazorWebAppOidc.Client)

Das BlazorWebAppOidc.Client-Projekt ist das clientseitige Projekt des Blazor Web App.

Die Klasse PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) ist ein clientseitiges AuthenticationStateProvider-Element, das den Authentifizierungsstatus der Benutzer bzw. Benutzerinnen bestimmt, indem nach Daten gesucht wird, die auf der Seite gespeicherten wurden, als diese auf dem Server gerendert wurde. Der Authentifizierungsstatus wird für die Lebensdauer der WebAssembly-Anwendung festgelegt.

Wenn sich Benutzer bzw. Benutzerinnen an- oder abmelden muss, muss die Seite vollständig neu geladen werden.

Die Beispiel-App stellt nur einen Benutzernamen und eine E-Mail für die Anzeige bereit. Es sind keine Token enthalten, die sich beim Senden von nachfolgenden Anforderungen beim Server authentifizieren und separat mithilfe eines cookie-Elements aus den HttpClient-Anforderungen an den Server verarbeitet werden.

Diese Version des Artikels behandelt die Implementierung von OIDC mit dem BFF-Muster (Back-End für Front-Ends). Ändern Sie die Artikelversionsauswahl in OIDC ohne BFF-Muster, wenn die Spezifikation der App das BFF-Muster nicht vorsieht.

Die folgende Spezifikation wird behandelt:

  • Die Blazor Web App verwendet den automatischen Rendermodus mit globaler Interaktivität.
  • Benutzerdefinierte Dienste für Authentifizierungsstatusanbieter werden von Server- und Client-Apps verwendet, um den Authentifizierungsstatus von Benutzern bzw. Benutzerinnen zu erfassen und zwischen Server und Client zu übertragen.
  • Diese App ist ein Ausgangspunkt für jeden OIDC-Authentifizierungsflow. OIDC wird manuell in der App konfiguriert und ist nicht auf Microsoft Entra ID oder Microsoft Identity Web-Pakete angewiesen, und die Beispiel-App erfordert kein Microsoft Azure-Hosting. Die Beispiel-App kann jedoch mit Entra und Microsoft Identity Web verwendet und in Azure gehostet werden.
  • Automatische nicht interaktive Tokenaktualisierung
  • Das Das BFF-Muster (Backend for Frontend) wird mit .NET Aspire für die Dienstermittlung und YARP für die Weiterleitung von Anfragen an einen Wettervorhersage-Endpunkt auf der Back-End-App übernommen.
    • Eine Backend-Web-API verwendet die JWT-Träger-Authentifizierung, um JWT-Tokens zu validieren, die von Blazor Web App in der Anmeldung cookie gespeichert wurden.
    • Aspire verbessert die Erfahrung beim Erstellen von cloudnativen .NET-Apps. Aspire bietet einen konsistenten, umfangreichen Satz von Tools und Mustern zum Erstellen und Ausführen verteilter Apps.
    • YARP (Yet Another Reverse Proxy) ist eine Bibliothek, die zum Erstellen eines Reverseproxyservers verwendet wird.

Weitere Informationen zu .NET Aspire finden Sie unter Allgemeine Verfügbarkeit von .NET Aspire: Vereinfachung der .NET Cloud-Native-Entwicklung (Mai, 2024).

Voraussetzungen

.NET Aspire erfordert Visual Studio Version 17.10 oder höher.

Beispiel-App

Die Beispiel-App umfasst fünf Projekte:

  • .NET Aspire:
    • Aspire.AppHost: Wird zum Verwalten der allgemeinen Orchestrierungsaspekte der App verwendet.
    • Aspire.ServiceDefaults: Enthält Standardkonfigurationen für .NET Aspire Apps, die nach Bedarf erweitert und angepasst werden können.
  • MinimalApiJwt: Back-End-Web-API mit einem Beispielendpunkt für die Minimal-API für Wetterdaten.
  • BlazorWebAppOidc: Server-seitiges Projekt der Blazor Web App.
  • BlazorWebAppOidc.Client: Client-seitiges Projekt der Blazor Web App.

Sie können über den Repositorystamm über folgenden Link auf die Beispiel-Apps im neuesten Versionsordner zugreifen. Die Projekte für .NET 8 oder höher befinden sich im Ordner BlazorWebAppOidcBff.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

.NET Aspire Projekte

Weitere Informationen zur Verwendung von .NET Aspire und Details zu den .AppHost- und .ServiceDefaults-Projekten der Beispiel-App finden Sie in der .NET Aspire-Dokumentation.

Bestätigen Sie, dass Sie die Voraussetzungen für .NET Aspire erfüllt haben. Weitere Informationen finden Sie im Abschnitt Voraussetzungen von Quickstart: Erstellen Ihrer ersten .NET Aspire App.

Die Beispiel-App konfiguriert nur ein unsicheres HTTP-Startprofil (http) für die Verwendung während der Entwicklungstests. Weitere Informationen, einschließlich eines Beispiels für unsichere und sichere Starteinstellungsprofile, finden Sie unter Zulassen von unsicherem Transport in .NET Aspire (.NET Aspire Dokumentation).

Server-seitiges Blazor Web App-Projekt (BlazorWebAppOidc)

Das BlazorWebAppOidc-Projekt ist das serverseitige Projekt des Blazor Web App. Das Projekt nutzt YARP zum Weiterleiten von Anforderungen per Proxy an einen Wettervorhersageendpunkt im Back-End-Web-API-Projekt (MinimalApiJwt). Das Zugriffstoken (access_token) wird dabei im cookie-Element für die Authentifizierung gespeichert.

Die Datei BlazorWebAppOidc.http kann zum Testen der Wetterdatenanforderung verwendet werden. Beachten Sie, dass das BlazorWebAppOidc-Projekt ausgeführt werden muss, um den Endpunkt zu testen, wobei der Endpunkt in der Datei hartcodiert ist. Weitere Informationen finden Sie unter Verwenden von HTTP-Dateien in Visual Studio 2022.

Hinweis

Das Serverprojekt verwendet IHttpContextAccessor/HttpContext, jedoch nie für interaktiv gerenderte Komponenten. Weitere Informationen finden Sie im Leitfaden zur Bedrohungsabwehr für das interaktive serverseitige Rendering von ASP.NET Core Blazor.

Konfiguration

In diesem Abschnitt wird erläutert, wie Sie die Beispiel-App konfigurieren.

Hinweis

Für Microsoft Entra ID und Azure AD B2C können Sie AddMicrosoftIdentityWebApp aus Microsoft Identity Web (NuGet-Paket Microsoft.Identity.Web, API-Dokumentation) verwenden. Damit werden der OIDC- und der Cookie-Authentifizierungshandler mit den entsprechenden Standardwerten hinzugefügt. Die Beispiel-App und die Anleitung in diesem Abschnitt verwenden nicht Microsoft Identity Web. Die Anleitung veranschaulicht, wie der OIDC-Handler manuell für die einzelnen OIDC-Anbieter konfiguriert wird. Weitere Informationen zur Implementierung von Microsoft Identity Web finden Sie in den verknüpften Ressourcen.

Die folgende OpenIdConnectOptions-Konfiguration befindet sich in der Datei Program des Projekts beim Aufruf von AddOpenIdConnect:

  • SignInScheme: Legt das Authentifizierungsschema fest, das der Middleware entspricht, die für die Speicherung der Benutzerdaten identity nach einer erfolgreichen Authentifizierung verantwortlich ist. Der OIDC-Handler muss ein Anmeldeschema verwenden, das Benutzeranmeldeinformationen über Anforderungen hinweg beibehalten kann. Die folgende Zeile dient ist lediglich der Veranschaulichung. Wird sie weggelassen, wird DefaultSignInScheme als Fallbackwert verwendet.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Bereiche für openid und profile (Scope) (Optional): Die Bereiche openid und profile werden ebenfalls standardmäßig konfiguriert, da Sie erforderlich sind, damit der OIDC-Handler funktioniert. Sie müssen jedoch möglicherweise erneut hinzugefügt werden, wenn Bereiche in der Authentication:Schemes:MicrosoftOidc:Scope-Konfiguration enthalten sind. Allgemeine Anleitungen zur Konfiguration finden Sie unter Konfiguration in ASP.NET Core und ASP.NET Core-Blazor-Konfiguration.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: Definiert, ob Zugriffs- und Aktualisierungstoken nach einer erfolgreichen Autorisierung in AuthenticationProperties gespeichert werden sollen. Der Wert wird auf true festgelegt, um Anforderungen für Wetterdaten aus dem Back-End-Web-API-Projekt (MinimalApiJwt) zu authentifizieren.

    oidcOptions.SaveTokens = true;
    
  • Bereich für den Offlinezugriff (Scope): Der Bereich offline_access ist für das Aktualisierungstoken erforderlich.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Bereiche zum Abrufen von Wetterdaten aus der Web-API (Scope): Der Bereich Weather.Get wird im Azure- oder Entra-Portal unter Eine API verfügbar machen konfiguriert. Dies ist erforderlich, damit das Back-End-Web-API-Projekt (MinimalApiJwt) das Zugriffstoken mit Bearer-JWT überprüft.

    oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
    

    Beispiel:

    • App-ID-URI ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
      • Verzeichnisname ({DIRECTORY NAME}): contoso
      • Anwendungs-ID (Client-ID) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • Bereich konfiguriert für Wetterdaten aus MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    

    Das obige Beispiel bezieht sich auf eine App, die in einem Mandanten mit einem AAD B2C-Mandantentyp registriert ist. Wenn die App in einem ME-ID-Mandanten registriert wurde, ist der App-ID-URI und damit der Bereich ein anderer.

    Beispiel:

    • App-ID-URI ({APP ID URI}): api://{CLIENT ID} mit Anwendungs-ID (Client-ID) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • Bereich konfiguriert für Wetterdaten aus MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    
  • Authority und ClientId: Legt die Autoritäts- und Client-ID für OIDC-Aufrufe fest.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Beispiel:

    • Autorität ({AUTHORITY}): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (verwendet Mandanten-ID a3942615-d115-4eb7-bc84-9974abcf5064)
    • Client-ID ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Beispiel für die Autorität „common“ von Microsoft Azure:

    Die Autorität „common“ sollte für mehrinstanzenfähige Apps verwendet werden. Sie können die Autorität „common“ auch für einzelinstanzenfähige Apps verwenden, allerdings ist ein benutzerdefinierter IssuerValidator-Wert erforderlich, wie weiter unten in diesem Abschnitt gezeigt.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret: Der geheimer OIDC-Clientschlüssel

    Das folgende Beispiel dient nur zu Test- und Demonstrationszwecken. Speichern Sie den geheimen Clientschlüssel nicht in der Assembly der App, und checken Sie den geheimen Schlüssel nicht in die Quellcodeverwaltung ein. Speichern Sie den geheimen Clientschlüssel unter Benutzergeheimnisse, in Azure Key Vault oder in einer Umgebungsvariablen.

    Die Konfiguration des Authentifizierungsschemas wird automatisch aus builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"] gelesen, wobei der {SCHEME NAME}-Platzhalter das Schema ist, das MicrosoftOidc ist. Da die Konfiguration vorkonfiguriert ist, kann ein geheimer Clientschlüssel automatisch über den Konfigurationsschlüssel Authentication:Schemes:MicrosoftOidc:ClientSecret gelesen werden. Benennen Sie auf dem Server mithilfe von Umgebungsvariablen die Umgebungsvariable Authentication__Schemes__MicrosoftOidc__ClientSecret:

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    Nur zu Demonstrations- und Testzwecken. ClientSecret kann direkt festgelegt werden. Legen Sie den Wert nicht direkt für bereitgestellte Produktions-Apps fest. Für etwas mehr Sicherheit müssen Sie die Zeile bedingt mit dem Symbol DEBUG kompilieren:

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    Beispiel:

    Geheimer Clientschlüssel ({CLIENT SECRET}): 463471c8c4...f90d674bc9 (für die Darstellung gekürzt)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType: Konfiguriert den OIDC-Handler so, dass nur der Autorisierungscodeflow ausgeführt wird. Implizite Genehmigungen und Hybridflows sind in diesem Modus nicht erforderlich.

    Aktivieren Sie in der App-Registrierungskonfiguration Implizite Genehmigung und Hybridflows im Entra- oder Azure-Portal *keins der Kontrollkästchen für den Autorisierungsendpunkt, um Zugriffstoken oder ID-Token zurückzugeben. Der OIDC-Handler fordert automatisch die entsprechenden Token mithilfe des vom Autorisierungsendpunkt zurückgegebenen Codes an.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaims und die Konfiguration von NameClaimType und RoleClaimType: Viele OIDC-Server verwenden name und role anstelle der Standardwerte für SOAP/WS-Fed in ClaimTypes. Wenn MapInboundClaims auf false festgelegt ist, führt der Handler keine Anspruchszuordnungen durch, und die Anspruchsnamen aus dem JWT werden direkt von der App verwendet. Im folgenden Beispiel wird der Rollenanspruchstyp auf roles festgelegt, wie für die Microsoft Entra-ID (ME-ID) passend. Weitere Informationen finden Sie in der Dokumentation Ihres identity Anbieters.

Hinweis

MapInboundClaims muss für die meisten OIDC-Anbieter auf false festgelegt werden, um das Umbenennen von Ansprüchen zu verhindern.

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
  • Pfadkonfiguration: Die Pfade müssen mit den bei der Registrierung der Anwendung beim OIDC-Anbieter konfigurierten Pfaden für den Umleitungs-URI (Anmelderückrufpfad) und für die Umleitung nach der Abmeldung (abgemeldeter Rückrufpfad) übereinstimmen. Im Azure-Portal werden Pfade auf dem Blatt Authentifizierung der App-Registrierung konfiguriert. Sowohl die Anmelde- als auch die Abmeldepfade müssen als Umleitungs-URIs registriert werden. Die Standardwerte sind /signin-oidc und /signout-callback-oidc.

    • CallbackPath: Der Anforderungspfad im Basispfad der Anwendung, an den der Benutzer-Agent zurückgegeben wird

      Legen Sie im Entra- oder Azure-Portal den Pfad im Umleitungs-URI der Plattformkonfiguration für Web fest:

      https://localhost/signin-oidc

      Hinweis

      Für localhost-Adressen ist kein Port erforderlich.

    • SignedOutCallbackPath: Der Anforderungspfad innerhalb des Basispfads der Anwendung, an den der Benutzeragent nach der Abmeldung vom identity-Anbieter zurückgegeben wird.

      Legen Sie im Entra- oder Azure-Portal den Pfad im Umleitungs-URI der Plattformkonfiguration für Web fest:

      https://localhost/signout-callback-oidc

      Hinweis

      Für localhost-Adressen ist kein Port erforderlich.

      Hinweis

      Bei Verwendung von Microsoft Identity Web leitet der Anbieter derzeit nur zurück an SignedOutCallbackPath um, wenn microsoftonline.com die Autorität (https://login.microsoftonline.com/{TENANT ID}/v2.0/) verwendet wird. Diese Einschränkung besteht nicht, wenn Sie die Autorität „common“ mit Microsoft Identity Web verwenden können. Weitere Informationen finden Sie unter postLogoutRedirectUri funktioniert nicht, wenn die Autoritäts-URL eine Mandanten-ID enthält (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: Unter diesem Pfad empfangene Anforderungen führen dazu, dass der Handler die Abmeldung mithilfe des Abmeldeschemas aufruft.

      Legen Sie im Entra- oder Azure-Portal die URL für Front-Channel-Abmeldung fest:

      https://localhost/signout-oidc

      Hinweis

      Für localhost-Adressen ist kein Port erforderlich.

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    Beispiele (Standardwerte):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure nur mit dem Endpunkt „common“) TokenValidationParameters.IssuerValidator: Viele OIDC-Anbieter arbeiten mit dem Standardaussteller-Validierungssteuerelement, wir müssen jedoch den Aussteller berücksichtigen, der mit der von https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration zurückgegebenen Mandanten-ID ({TENANT ID}) parametrisiert ist. Weitere Informationen finden Sie unter SecurityTokenInvalidIssuerException bei OpenID Connect und beim Azure AD-Endpunkt „common“ (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731).

    Nur für Apps, die Microsoft Entra ID oder Azure AD B2C mit dem Endpunkt „common“ verwenden:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Code der Beispiel-App

Sehen Sie sich die folgenden Features der Beispiel-App an:

  • Automatische, nicht interaktive Tokenaktualisierung mithilfe einer benutzerdefinierten cookie-Aktualisierung (CookieOidcRefresher.cs)
  • Die Klasse PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) ist ein serverseitiges AuthenticationStateProvider-Element, das PersistentComponentState verwendet, um den Authentifizierungsstatus an den Client zu senden, der dann für die Lebensdauer der WebAssembly-Anwendung festgelegt wird.
  • Anfragen an das Blazor Web App werden an das Backend-Web-API-Projekt (MinimalApiJwt) weitergeleitet. MapForwarder in der Datei Program fügt eine direkte Weiterleitung von HTTP-Anforderungen, die dem angegebenen Muster entsprechen, an ein bestimmtes Ziel hinzu. Dabei werden die Standardkonfiguration für die ausgehende Anfrage, angepasste Transformationen und der Standard-HTTP-Client verwendet.
    • Beim Rendern der Weather Komponente auf dem Server verwendet die Komponente die ServerWeatherForecaster Proxyanforderung für Wetterdaten mit dem Zugriffstoken des Benutzers.
    • Wenn die Komponente auf dem Client gerendert wird, verwendet die Komponente die ClientWeatherForecaster Dienstimplementierung, die eine vorkonfigurierte HttpClient (in der Datei des Clientprojekts Program ) verwendet, um einen Web-API-Aufruf an das Serverprojekt durchzuführen. Ein minimaler API-Endpunkt (/weather-forecast), der in der Datei des Serverprojekts Program definiert ist, transformiert die Anforderung mit dem Zugriffstoken des Benutzers, um die Wetterdaten abzurufen.

Weitere Informationen zu (Web-)API-Aufrufen unter Verwendung von Dienstabstraktionen in Blazor Web Apps finden Sie unter Aufruf einer Web-API von einer ASP.NET Core-Blazor-App.

Client-seitiges Blazor Web App Projekt (BlazorWebAppOidc.Client)

Das BlazorWebAppOidc.Client-Projekt ist das clientseitige Projekt des Blazor Web App.

Die Klasse PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) ist ein clientseitiges AuthenticationStateProvider-Element, das den Authentifizierungsstatus der Benutzer bzw. Benutzerinnen bestimmt, indem nach Daten gesucht wird, die auf der Seite gespeicherten wurden, als diese auf dem Server gerendert wurde. Der Authentifizierungsstatus wird für die Lebensdauer der WebAssembly-Anwendung festgelegt.

Wenn sich Benutzer bzw. Benutzerinnen an- oder abmelden muss, muss die Seite vollständig neu geladen werden.

Die Beispiel-App stellt nur einen Benutzernamen und eine E-Mail für die Anzeige bereit. Es sind keine Token enthalten, die sich beim Senden von nachfolgenden Anforderungen beim Server authentifizieren und separat mithilfe eines cookie-Elements aus den HttpClient-Anforderungen an den Server verarbeitet werden.

Back-End-Web-API-Projekt (MinimalApiJwt)

Das Projekt MinimalApiJwt ist eine Back-End-Web-API für mehrere Front-End-Projekte. Das Projekt konfiguriert einen Endpunkt für die Minimal-API für Wetterdaten. Anfragen aus dem Blazor Web App server-seitigen Projekt (BlazorWebAppOidc) werden an das MinimalApiJwt-Projekt weitergeleitet.

Konfiguration

Konfigurieren Sie das Projekt in JwtBearerOptions des AddJwtBearer-Aufrufs in der Datei Program des Projekts:

  • Audience: Legt die Zielgruppe für alle empfangenen OpenID Connect-Token fest.

    Im Azure- oder Entra-Portal: Passen Sie den Wert nur an den Pfad des Anwendungs-ID-URI an, der beim Hinzufügen des Bereichs Weather.Get unter Eine API verfügbar machen konfiguriert wird:

    jwtOptions.Audience = "{APP ID URI}";
    

    Beispiel:

    App-ID-URI ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}:

    • Verzeichnisname ({DIRECTORY NAME}): contoso
    • Anwendungs-ID (Client-ID) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    jwtOptions.Audience = "https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Das obige Beispiel bezieht sich auf eine App, die in einem Mandanten mit einem AAD B2C-Mandantentyp registriert ist. Wenn die App in einem ME-ID-Mandanten registriert wurde, ist der App-ID-URI und damit die Zielgruppe anders.

    Beispiel:

    App-ID-URI ({APP ID URI}): api://{CLIENT ID} mit Anwendungs-ID (Client-ID) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f

    jwtOptions.Audience = "api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    
  • Authority: Legt die Autorität für OpenID Connect-Aufrufe fest. Stimmen Sie den Wert auf die für den OIDC-Handler konfigurierte Autorität in BlazorWebAppOidc/Program.cs ab:

    jwtOptions.Authority = "{AUTHORITY}";
    

    Beispiel:

    Autorität ({AUTHORITY}): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (verwendet Mandanten-ID a3942615-d115-4eb7-bc84-9974abcf5064)

    jwtOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    

    Das obige Beispiel bezieht sich auf eine App, die in einem Mandanten mit einem AAD B2C-Mandantentyp registriert ist. Wenn die App in einem ME-ID-Tenant registriert ist, sollte die Autorität mit dem Aussteller (iss) des vom identity-Anbieter zurückgegebenen JWT übereinstimmen:

    jwtOptions.Authority = "https://sts.windows.net/a3942615-d115-4eb7-bc84-9974abcf5064/";
    

Minimal-API für Wetterdaten

Sicherer Wettervorhersagedaten-Endpunkt in der Datei Program des Projekts:

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

Für die RequireAuthorization-Erweiterungsmethode ist eine Autorisierung für die Routendefinition erforderlich. Fügen Sie für alle Controller, die Sie dem Projekt hinzufügen, das [Authorize]-Attribut dem Controller oder der Aktion hinzu.

Hinzufügen von Komponenten, die interaktives serverseitiges Rendering übernehmen

Da die App das globale interaktive Autorendering über die Routes Komponente verwendet, werden einzelne Komponenten, die interaktives serverseitiges Rendering (interaktives SSR, @rendermode InteractiveServer) in ihrer Komponentendefinitionsdatei (.razor) angeben, im Ordner des .ClientProjektsPages platziert.

Das Platzieren interaktiver SSR-Komponenten im .Client Projekt ist kontraintuitiv, da diese Komponenten nur auf dem Server gerendert werden.

Wenn Sie eine interaktive SSR-Komponente im Components/Pages Ordner des Serverprojekts platzieren, wird die Komponente normal und kurz im Browser des Benutzers angezeigt. Der clientseitige Router ist jedoch nicht in der Lage, die Komponente zu finden, was letztendlich zum Fehler 404 - Nicht gefunden führt.

Platzieren Sie daher interaktive SSR-Komponenten im Pages Ordner des .Client Projekts.

Umleitung auf die home-Seite bei der Abmeldung

Wenn Benutzer durch die App navigieren, legt die LogInOrOut-Komponente (Layout/LogInOrOut.razor) ein ausgeblendetes Feld für die Rückgabe-URL (ReturnUrl) auf den Wert der aktuellen URL (currentURL) fest. Wenn sich der Nutzende von der App abmeldet, kehrt der identity-Anbieter zu der Seite zurück, von der er sich abgemeldet hat.

Wenn sich Benutzer von einer sicheren Seite abmelden, gelangen sie nach dem Abmelden zur gleichen sicheren Seite und von dort aus zurück zum Authentifizierungsprozess. Dieses Verhalten ist in Ordnung, wenn Benutzer häufig die Konten wechseln müssen. Eine alternative Anwendungsspezifikation kann jedoch vorsehen, dass der Benutzende nach der Abmeldung auf die home-Seite der Anwendung oder eine andere Seite zurückkehrt. Das folgende Beispiel zeigt, wie Sie die home-Seite der App als Rückgabe-URL für Abmeldevorgänge festlegen.

Die wichtigen Änderungen an der LogInOrOut-Komponente werden im folgenden Beispiel veranschaulicht. Der value des verborgenen Feldes für die ReturnUrl wird auf die home-Seite bei / gesetzt. IDisposable wird nicht mehr implementiert. NavigationManager wird nicht mehr eingefügt. Der gesamte @code-Block wird entfernt.

Layout/LogInOrOut.razor:

@using Microsoft.AspNetCore.Authorization

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <input type="hidden" name="ReturnUrl" value="/" />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout @context.User.Identity?.Name
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> 
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

Kryptografische Nonce

Eine Nonce ist ein Zeichenfolgenwert, der der Sitzung eines Clients einem ID-Token zuordnet, um Replay-Angriffe zu minimieren.

Wenn Sie während der Authentifizierungsentwicklung und -tests einen Nonce-Fehler erhalten, verwenden Sie für jede Testausführung eine neue InPrivate/Inkognito-Browsersitzung, unabhängig davon, wie klein die Änderung an der App oder dem Testbenutzer ist, da veraltete cookie Daten zu einem Nonce-Fehler führen können. Weitere Informationen finden Sie im Abschnitt Cookies und Standortdaten.

Eine Nonce ist nicht erforderlich oder wird nicht verwendet, wenn ein Aktualisierungstoken für ein neues Zugriffstoken ausgetauscht wird. In der Beispiel-App wird OpenIdConnectProtocolValidator.RequireNonce durch dieCookieOidcRefresher( CookieOidcRefresher.cs ) absichtlich auf false gesetzt.

Anwendungsrollen für Apps, die nicht bei Microsoft Entra registriert sind (ME-ID)

Dieser Abschnitt bezieht sich auf Anwendungen, die nicht Microsoft Entra ID (ME-ID) als identity Provider verwenden. Informationen zu Apps, die bei ME-ID registriert sind, finden Sie im Abschnitt Anwendungsrollen für Apps, die bei Microsoft Entra (ME-ID) registriert sind.

Konfigurieren Sie den Rollenanspruchstyp (TokenValidationParameters.RoleClaimType) in OpenIdConnectOptions von Program.cs:

oidcOptions.TokenValidationParameters.RoleClaimType = "{ROLE CLAIM TYPE}";

Bei vielen OIDC identity-Anbietern ist die Rollenanspruchsart role. Überprüfen Sie die Dokumentation Ihres identity-Anbieters auf den richtigen Wert.

Ersetzen Sie die UserInfo-Klasse im BlazorWebAppOidc.Client-Projekt durch die folgende Klasse.

UserInfo.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "role";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

Für Razor-Komponenten ist nun rollenbasierte und richtlinienbasierte Autorisierung möglich. Anwendungsrollen werden in role-Ansprüchen angezeigt – ein Anspruch pro Rolle.

Anwendungsrollen für Apps, die bei Microsoft Entra (ME-ID) registriert sind

Befolgen Sie die Anleitungen in diesem Abschnitt, um Anwendungsrollen, ME-ID-Sicherheitsgruppen und integrierte ME-ID-Adminrollen für Apps mit Microsoft Entra ID (ME-ID) zu implementieren.

Der in diesem Abschnitt beschriebene Ansatz konfiguriert ME-ID so, dass Gruppen und Rollen im Authentifizierungs-Header cookie gesendet werden. Wenn Benutzende nur Mitglied einiger weniger Sicherheitsgruppen und -rollen sind, sollte der folgende Ansatz für die meisten Hosting-Plattformen funktionieren, ohne dass es zu Problemen mit zu langen Headern kommt, z. B. bei IIS-Hosting, das über eine Standard-Header-Längenbegrenzung von 16 KB (MaxRequestBytes) verfügt. Wenn die Länge des Headers aufgrund einer hohen Anzahl an Gruppen- oder Rollenmitgliedschaften ein Problem darstellt, empfehlen wir, die Anleitung in diesem Abschnitt nicht zu befolgen und stattdessen Microsoft Graph zu implementieren, um die Gruppen und Rollen von Benutzenden separat von der ME-ID abzurufen. Dieser Ansatz führt nicht zu einer Vergrößerung der Authentifizierung cookie. Weitere Informationen finden Sie unter Ungültige Anforderung – Anforderung zu lang – IIS-Server (dotnet/aspnetcore #57545).

Konfigurieren Sie den Rollenanspruchstyp (TokenValidationParameters.RoleClaimType) in OpenIdConnectOptions von Program.cs. Legen Sie den Wert auf roles fest:

oidcOptions.TokenValidationParameters.RoleClaimType = "roles";

Zwar können Sie ohne ME-ID-Premium-Konto nicht Rollen zu Gruppen zuweisen, aber Sie können Benutzenden Rollen zuweisen und Rollenansprüche für Benutzende mit einem Azure-Standardkonto erhalten. Für die Schritte in diesem Abschnitt ist kein ME-ID Premium-Konto erforderlich.

Befolgen Sie beim Arbeiten mit dem Standardverzeichnis die Anweisungen unter Anwendungsrollen zu Ihrer Anwendung hinzufügen und im Token empfangen (ME-ID-Dokumentation), um Rollen zu konfigurieren und zuzuweisen. Wenn Sie nicht mit dem Standardverzeichnis arbeiten, bearbeiten Sie das Manifest der App im Azure-Portal, um die Rollen der App manuell im appRoles-Eintrag der Manifestdatei einzurichten. Weitere Informationen finden Sie unter Rollenanspruch konfigurieren (ME-ID-Dokumentation).

Die Azure-Sicherheitsgruppen von Benutzenden kommen in groups-Ansprüchen an, und die integrierten Rollenzuweisungen für ME-ID-Admins von Benutzenden kommen in bekannten IDs (wids-Ansprüche) an. Werte für beide Anspruchstypen sind GUIDs. Wenn sie von der App empfangen werden, können diese Ansprüche verwendet werden, um die Rollen- und Richtlinienautorisierung in Razor-Komponenten einzurichten.

Legen Sie im Azure-Portal im App-Manifest das groupMembershipClaims-Attribut auf All fest. Beim Wert All sendet ME-ID alle Sicherheits-/Verteilergruppen (groups-Ansprüche) und Rollen (wids-Ansprüche) der angemeldeten Benutzenden. Um das groupMembershipClaims-Attribut festzulegen:

  1. Öffnen Sie die App-Registrierungen im Azure-Portal.
  2. Wählen Sie in der Randleiste Verwalten>Manifest aus.
  3. Suchen Sie das groupMembershipClaims-Attribut.
  4. Legen Sie den Wert auf All fest ("groupMembershipClaims": "All").
  5. Wählen Sie die Schaltfläche Speichern aus.

Ersetzen Sie die UserInfo-Klasse im BlazorWebAppOidc.Client-Projekt durch die folgende Klasse.

UserInfo.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }
    public required string[] Groups { get; init; }
    public required string[] Wids { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "roles";
    private const string GroupsClaimType = "groups";
    private const string WidsClaimType = "wids";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
            Groups = principal.FindAll(GroupsClaimType).Select(c => c.Value)
                .ToArray(),
            Wids = principal.FindAll(WidsClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat(Groups.Select(role => new Claim(GroupsClaimType, role)))
                .Concat(Wids.Select(role => new Claim(WidsClaimType, role)))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

Für Razor-Komponenten ist nun rollenbasierte und richtlinienbasierte Autorisierung möglich:

  • Anwendungsrollen werden in roles-Ansprüchen angezeigt – ein Anspruch pro Rolle.
  • Sicherheitsgruppen werden in groups-Ansprüchen angezeigt – ein Anspruch pro Gruppe. Die Sicherheitsgruppen-GUIDs werden im Azure-Portal angezeigt, wenn Sie eine Sicherheitsgruppe erstellen und wenn Sie beim Auswählen von Identity>Übersicht>Gruppen>Ansicht aufgeführt werden.
  • Integrierte ME-ID-Adminrollen werden in wids-Ansprüchen angezeigt – ein Anspruch pro Rolle. Der wids-Anspruch mit einem Wert von b79fbf4d-3ef9-4689-8143-76b194e85509 wird immer von ME-ID für Nicht-Gastkonten der Mandantin bzw. des Mandanten gesendet und verweist nicht auf eine Adminrolle. Adminrollen-GUIDs (Rollenvorlagen-IDs) werden im Azure-Portal angezeigt, wenn Sie Rollen und Administratoren auswählen, gefolgt von den Auslassungspunkten (...) >Beschreibung für die aufgeführte Rolle. Die Rollenvorlagen-IDs werden auch in integrierten Microsoft Entra-Rollen (Entra-Dokumentation) aufgeführt.

Problembehandlung

Logging

Die Server-App ist eine Standard-ASP.NET Core-App. Weitere Informationen finden Sie in den ASP.NET Core-Protokollierungsanleitungen zum Aktivieren einer niedrigeren Protokollierungsebene in der Server-App.

Informationen zum Aktivieren der Debug- oder Ablaufverfolgungsprotokollierung für die Blazor WebAssembly-Authentifizierung finden Sie im Abschnitt zur clientseitigen Authentifizierungsprotokollierung ASP.NET Core-Blazor-Protokollierung, wobei die Artikelversionsauswahl auf ASP.NET Core 7.0 oder höher festgelegt ist.

Häufige Fehler

  • Falsche Konfiguration der App oder des Identity-Anbieters (Identity Provider, IP)

    Die häufigsten Fehler werden durch eine falsche Konfiguration verursacht. Im Folgenden finden Sie einige Beispiele:

    • In Abhängigkeit von den Anforderungen des Szenarios verhindert eine fehlende oder falsche Autorität, Instanz, Mandanten-ID, Mandantendomäne oder Client-ID oder ein fehlender oder falscher Umleitungs-URI, dass Clients von einer App authentifiziert werden.
    • Falsche Anforderungsbereiche verhindern, dass Clients auf die Web-API-Endpunkte des Servers zugreifen können.
    • Falsche oder fehlende Server-API-Berechtigungen verhindern, dass Clients auf Server-Web-API-Endpunkte zugreifen können.
    • Das Ausführen der App an einem anderen Port als dem, der im Umleitungs-URI der App-Registrierung für die IP konfiguriert ist. Beachten Sie, dass für Microsoft Entra ID und eine App, die an einer localhost-Entwicklungstestadresse ausgeführt wird, kein Port erforderlich ist. Die Portkonfiguration der App und der Port, an dem die App ausgeführt wird, müssen jedoch für Nicht-localhost-Adressen übereinstimmen.

    Die Konfigurationsabdeckung in diesem Artikel enthält Beispiele für die richtige Konfiguration. Überprüfen Sie sorgfältig die Konfiguration, die nach App- und IP-Fehlkonfigurationen sucht.

    Wenn die Konfiguration anscheinend korrekt ist:

    • Analysieren Sie Anwendungsprotokolle.

    • Überprüfen Sie den Netzwerkdatenverkehr zwischen der Client-App und dem IP oder der Server-App mit den Entwicklertools des Browsers. Häufig wird vom IP oder von der Server-App eine präzise Fehlermeldung oder eine Meldung mit einem Hinweis auf die Ursache des Problems zurückgegeben, nachdem eine Anforderung erfolgt ist. Anleitungen zu den Entwicklertools finden Sie in den folgenden Artikeln:

    Das Dokumentationsteam berücksichtigt Feedback zur Dokumentation und zu Fehlern in Artikeln. (Legen Sie im Feedbackbereich auf dieser Seite ein Ticket an.) Es leistet jedoch keinen Produktsupport. Es gibt einige öffentliche Supportforen, die bei der Problembehandlung für eine App weiterhelfen. Es wird Folgendes empfohlen:

    Die genannten Foren werden nicht von Microsoft betrieben oder kontrolliert.

    Bei nicht sicherheitsbezogenen, nicht sensiblen und nicht vertraulichen Fehlerberichten zum Framework wird legen Sie ein Ticket für die ASP.NET Core-Produkteinheit an. Legen Sie ein Ticket für die Produkteinheit erst an, wenn Sie die Ursache eines Problems gründlich untersucht haben und es nicht selbst oder mithilfe der Community in einem öffentlichen Supportforum lösen konnten. Die Produkteinheit kann keine Problembehandlung für einzelne Apps durchführen, die aufgrund einer einfachen Fehlkonfiguration oder in Anwendungsfällen mit Drittanbieterdiensten nicht funktionieren. Wenn ein Bericht sensibler oder vertraulicher Natur ist oder eine potenzielle Sicherheitslücke im Produkt beschreibt, die von Cyberkriminellen ausgenutzt werden könnte, lesen Sie bitte Melden von Sicherheitsproblemen und Fehlern (dotnet/aspnetcore GitHub Repository).

  • Nicht autorisierter Client für ME-ID

    Info: Die Autorisierung von Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization ist fehlgeschlagen. Diese Anforderungen wurden nicht erfüllt: DenyAnonymousAuthorizationRequirement: Erfordert einen authentifizierten Benutzer.

    Anmelderückruffehler von ME-ID:

    • Fehler: unauthorized_client
    • Description (Beschreibung): AADB2C90058: The provided application is not configured to allow public clients.

    So beheben Sie den Fehler

    1. Greifen Sie im Azure-Portal auf das Manifest der App zu.
    2. Legen Sie das allowPublicClient-Attribut auf null oder true fest.

Cookies und Standortdaten

Cookies und Standortdaten können über App-Updates hinweg beibehalten werden und das Testen und die Problembehandlung beeinträchtigen. Entfernen Sie Folgendes, wenn Sie Änderungen am App-Code, Änderungen an den Benutzerkonten beim Anbieter oder Konfigurationsänderungen an Anbieter-Apps vornehmen:

  • Anmelde-Cookies von Benutzern
  • App-Cookies
  • Zwischengespeicherte und gespeicherte Standortdaten

Ein Ansatz, um zu verhindern, dass veraltete Cookies und Standortdaten das Testen und die Problembehandlung beeinträchtigen, ist folgender:

  • Browser konfigurieren
    • Verwenden Sie zum Testen einen Browser, den Sie so konfigurieren können, dass alle cookies und Standortdaten jedes Mal gelöscht werden, wenn der Browser geschlossen wird.
    • Stellen Sie sicher, dass der Browser manuell oder durch die IDE für alle Änderungen an der App, dem Testbenutzer oder der Anbieterkonfiguration geschlossen wird.
  • Verwenden Sie einen benutzerdefinierten Befehl, um in Visual Studio einen Browser im privaten oder Inkognito-Modus zu öffnen:
    • Öffnen Sie mithilfe der Schaltfläche Ausführen von Visual Studio das Dialogfeld Browserauswahl.
    • Wählen Sie die Schaltfläche Hinzufügen aus.
    • Geben Sie im Feld Programm den Pfad zu Ihrem Browser an. Die folgenden Pfade für ausführbare Dateien sind typische Installationspfade für Windows 10. Wenn Ihr Browser an einem anderen Speicherort installiert ist oder Sie nicht Windows 10 verwenden, geben Sie den Pfad zur ausführbaren Datei des Browsers an.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • Geben Sie im Feld Argumente die Befehlszeilenoption an, die der Browser verwendet, um im privaten oder Inkognito-Modus geöffnet zu werden. Für einige Browser ist die URL der App erforderlich.
      • Microsoft Edge: Verwenden Sie -inprivate.
      • Google Chrome: Verwenden Sie --incognito --new-window {URL}, wobei der Platzhalter {URL} die zu öffnende URL ist (z. B. https://localhost:5001).
      • Mozilla Firefox: Verwenden Sie -private -url {URL}, wobei der Platzhalter {URL} die zu öffnende URL ist (z. B. https://localhost:5001).
    • Geben Sie im Feld Anzeigename einen Namen ein. Beispielsweise Firefox Auth Testing.
    • Klicken Sie auf die Schaltfläche OK.
    • Um zu vermeiden, dass das Browserprofil für jede einzelne Testiteration einer App ausgewählt werden muss, legen Sie das Profil mithilfe der Schaltfläche Als Standard festlegen als Standard fest.
    • Stellen Sie sicher, dass der Browser von der IDE für alle Änderungen an der App, dem Testbenutzer oder der Anbieterkonfiguration geschlossen wird.

App-Upgrades

Eine funktionsfähige App kann direkt nach der Durchführung eines Upgrades für das .NET Core SDK auf dem Entwicklungscomputer oder einer Änderung der Paketversionen in der App fehlschlagen. In einigen Fällen können inkohärente Pakete eine App beschädigen, wenn größere Upgrades durchgeführt werden. Die meisten dieser Probleme können durch Befolgung der folgenden Anweisungen behoben werden:

  1. Löschen Sie die Caches für NuGet-Pakete auf dem lokalen System, indem Sie dotnet nuget locals all --clear in einer Befehlsshell ausführen.
  2. Löschen Sie die Ordner bin und obj des Projekts.
  3. Stellen Sie das Projekt wieder her und erstellen Sie es neu.
  4. Löschen Sie alle Dateien im Bereitstellungsordner auf dem Server, bevor Sie die App noch mal bereitstellen.

Hinweis

Die Verwendung von Paketversionen, die mit dem Zielframework der App nicht kompatibel sind, wird nicht unterstützt. Informationen zu einem Paket finden Sie mithilfe der NuGet Gallery oder des FuGet Package Explorer.

Ausführen der Server-App

Stellen Sie beim Testen und bei der Fehlerbehebung Blazor Web App sicher, dass Sie die Anwendung über das Serverprojekt ausführen.

Überprüfen des Benutzers

Die folgende UserClaims-Komponente kann direkt in Anwendungen verwendet werden oder als Grundlage für weitere Anpassungen dienen.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    [CascadingParameter]
    private Task<AuthenticationState>? AuthState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

Zusätzliche Ressourcen