Freigeben über


Authentifizierung und Autorisierung

Tipp

Diese Inhalte sind ein Auszug aus dem eBook „Enterprise Application Patterns Using .NET MAUI“, verfügbar unter .NET Docs oder als kostenlos herunterladbare PDF-Datei, die offline gelesen werden kann.

Enterprise Application Patterns Using .NET MAUI (Miniaturansicht des E-Book-Deckblatts)

Die Authentifizierung ist der Prozess, bei dem Benutzeranmeldeinformationen wie z. B. Name und Kennwort abgerufen und gegenüber einer Autorität geprüft werden. Die Entität, die die Anmeldeinformationen übermittelt hat, gilt als authentifizierte Identität, wenn diese gültig sind. Nachdem eine Identität eingerichtet wurde, bestimmt ein Autorisierungsprozess, ob diese Zugriff auf eine bestimmte Ressource hat.

Es gibt viele Ansätze für die Integration von Authentifizierung und Autorisierung in eine .NET MAUI-App, die mit einer ASP.NET-Webanwendung kommuniziert, einschließlich der Verwendung von ASP.NET Core Identity, externen Authentifizierungsanbietern wie Microsoft, Google, Facebook oder Twitter und Authentifizierungsmiddleware. Die Multi-Plattform-App „eShop“ führt die Authentifizierung und Autorisierung mit einem Microservice für containerisierte Identitäten durch, der IdentityServer verwendet. Die App fordert mehrere Sicherheitstoken von IdentityServer an, um eine*n Benutzer*in zu authentifizieren oder auf eine Ressource zuzugreifen. Damit IdentityServer im Namen von Benutzer*innen Token ausstellen kann, muss sich der oder die Benutzer*in bei IdentityServer anmelden. IdentityServer hat jedoch keine Benutzeroberfläche oder Datenbank für die Authentifizierung. Daher wird in der Referenzanwendung „eShop“ ASP.NET Core Identity für diesen Zweck verwendet.

Authentifizierung

Die Authentifizierung ist erforderlich, wenn eine Anwendung die Identität des oder der aktuellen Benutzer*in kennen muss. Der primäre Mechanismus von ASP.NET Core zum Identifizieren von Benutzer*innen ist das Mitgliedschaftssystem „ASP.NET Core Identity“, das Benutzerinformationen in einem von dem oder der Entwickler*in konfigurierten Datenspeicher speichert. In der Regel handelt es sich bei diesem Datenspeicher um einen Entity Framework-Speicher, obwohl benutzerdefinierte Speicher oder Drittanbieterpakete zum Speichern von Identitätsinformationen in Azure Storage, DocumentDB oder anderen Speicherorten verwendet werden können.

Für Authentifizierungsszenarios, die einen lokalen Benutzerdatenspeicher verwenden und Identitätsinformationen anforderungsübergreifend mithilfe von Cookies speichern (wie in ASP.NET-Webanwendungen üblich), ist ASP.NET Core Identity eine geeignete Lösung. Cookies sind jedoch nicht immer das übliche Mittel zum Speichern und Übertragen von Daten. Beispielsweise muss eine ASP.NET Core-Webanwendung, die RESTful-Endpunkte verfügbar macht, auf die über eine App zugegriffen wird, in der Regel die Bearertokenauthentifizierung verwenden, da Cookies in diesem Szenario nicht verwendet werden können. Bearertoken können jedoch problemlos abgerufen und in den Autorisierungsheader von Webanforderungen aufgenommen werden, die von der App gesendet werden.

Ausstellen von Bearertoken mithilfe von IdentityServer

IdentityServer ist ein Open-Source-Framework mit OpenID Connect und OAuth 2.0 für ASP.NET Core, das für viele Authentifizierungs- und Autorisierungsszenarios verwendet werden kann, einschließlich der Ausgabe von Sicherheitstoken für lokale ASP.NET Core Identity-Benutzer*innen.

Hinweis

OpenID Connect und OAuth 2.0 sind sehr ähnlich, haben jedoch unterschiedliche Zuständigkeiten.

OpenID Connect ist eine Authentifizierungsschicht, die auf dem OAuth 2.0-Protokoll aufbaut. OAuth 2 ist ein Protokoll, mit dem Anwendungen Zugriffstoken von einem Sicherheitstokendienst anfordern und für die Kommunikation mit APIs verwenden können. Diese Delegierung reduziert die Komplexität sowohl in Clientanwendungen als auch in APIs, da Authentifizierung und Autorisierung zentralisiert werden können.

OpenID Connect und OAuth 2.0 kombinieren die beiden grundlegenden Sicherheitsaspekte der Authentifizierung und des API-Zugriffs, und IdentityServer ist eine Implementierung dieser Protokolle.

In Anwendungen, die eine direkte Client-zu-Microservice-Kommunikation verwenden, z. B. die Referenzanwendung „eShop“, kann ein dedizierter Authentifizierungsmicroservice für die Benutzerauthentifizierung verwendet werden, der als Sicherheitstokendienst (Security Token Service, STS) fungiert. Dieser Ablauf wird im folgenden Diagramm dargestellt. Weitere Informationen zur direkten Client-zu-Microservice-Kommunikation finden Sie unter Microservices.

Authentifizierung durch einen dedizierten Authentifizierungsmicroservice

Die Multi-Plattform-App „eShop“ kommuniziert mit dem Identitätsmicroservice, der IdentityServer für die Authentifizierung und die Zugriffssteuerung für APIs verwendet. Daher fordert die Multi-Plattform-App Token von IdentityServer an, die entweder der Authentifizierung von Benutzer*innen oder dem Zugriff auf Ressourcen dienen:

  • Die Authentifizierung von Benutzer*innen mit IdentityServer erfolgt durch die Multi-Plattform-App, die ein Identitätstoken anfordert, das das Ergebnis eines Authentifizierungsprozesses darstellt. Es enthält mindestens einen Bezeichner für den oder die Benutzer*in und Informationen darüber, wie und wann der oder die Benutzer*in authentifiziert wird. Es kann auch zusätzliche Identitätsdaten enthalten.
  • Der Zugriff auf eine Ressource mit IdentityServer erfolgt durch die Multi-Plattform-App, die ein Zugriffstoken anfordert, das den Zugriff auf eine API-Ressource ermöglicht. Clients fordern Zugriffstoken an und leiten sie an die API weiter. Zugriffstoken enthalten Informationen über den Client und den oder die Benutzer*in, sofern vorhanden. APIs verwenden diese Informationen dann, um den Zugriff auf ihre Daten zu autorisieren.

Hinweis

Ein Client muss bei IdentityServer registriert werden, bevor erfolgreich Token angefordert werden können. Weitere Informationen zum Hinzufügen von Clients finden Sie unter Definieren von Clients.

Hinzufügen von IdentityServer zu einer Webanwendung

Damit eine ASP.NET Core-Webanwendung IdentityServer verwenden kann, muss sie der Visual Studio-Projektmappe der Webanwendung hinzugefügt werden. Weitere Informationen finden Sie unter Setup und Übersicht in der IdentityServer-Dokumentation. Sobald IdentityServer in der Visual Studio-Projektmappe für die Webanwendung enthalten ist, muss der Dienst der HTTP-Anforderungsverarbeitungspipeline hinzugefügt werden, um Anforderungen an OpenID Connect- und OAuth 2.0-Endpunkte verarbeiten zu können. Dieser Parameter ist in der Datei Identity.APIProgram.cs des Projekts konfiguriert, wie im folgenden Codebeispiel dargestellt:


...

app.UseIdentityServer();

Die Reihenfolge ist in der HTTP-Anforderungsverarbeitungspipeline der Webanwendung wichtig. Aus diesem Grund muss IdentityServer der Pipeline vor dem Benutzeroberflächenframework hinzugefügt werden, das den Anmeldebildschirm implementiert.

Konfigurieren von IdentityServer

IdentityServer wird im Identity.APIProgram.cs des Projekts konfiguriert. Hierzu wird die Methode AddIdentityServer aufgerufen, wie im folgenden Codebeispiel aus der eShop-Referenzanwendung dargestellt ist.

builder.Services.AddIdentityServer(options =>
    {
        options.Authentication.CookieLifetime = TimeSpan.FromHours(2);
    
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
    
        // TODO: Remove this line in production.
        options.KeyManagement.Enabled = false;
    })
    .AddInMemoryIdentityResources(Config.GetResources())
    .AddInMemoryApiScopes(Config.GetApiScopes())
    .AddInMemoryApiResources(Config.GetApis())
    .AddInMemoryClients(Config.GetClients(builder.Configuration))
    .AddAspNetIdentity<ApplicationUser>()
    // TODO: Not recommended for production - you need to store your key material somewhere secure
    .AddDeveloperSigningCredential();

Nach dem Aufrufen der services.AddIdentityServer-Methode werden zusätzliche Fluent-APIs aufgerufen, um Folgendes zu konfigurieren:

  • Die Anmeldeinformationen, die zum Signieren verwendet werden
  • Die API- und Identitätsressourcen, auf die Benutzer*innen möglicherweise Zugriff anfordern
  • Die Clients, die eine Verbindung herstellen, um Token anzufordern
  • ASP.NET Core Identity

Tipp

Laden Sie die IdentityServer-Konfiguration dynamisch. Die APIs von IdentityServer ermöglichen das Konfigurieren von IdentityServer über eine In-Memory-Liste mit Konfigurationsobjekten. In der Referenzanwendung „eShop“ werden diese In-Memory-Sammlungen in die Anwendung hartcodiert. In Produktionsszenarios können sie jedoch dynamisch aus einer Konfigurationsdatei oder aus einer Datenbank geladen werden.

Weitere Informationen zum Konfigurieren von IdentityServer für die Verwendung von ASP.NET Core Identity finden Sie unter Verwenden von ASP.NET Core Identity in der IdentityServer-Dokumentation.

Konfigurieren von API-Ressourcen

Beim Konfigurieren von API-Ressourcen erwartet die AddInMemoryApiResources-Methode eine IEnumerable<ApiResource>-Sammlung. Das folgende Codebeispiel zeigt die GetApis-Methode, die diese Sammlung in der eShop-Referenzanwendung bereitstellt:

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiScope("orders", "Orders Service"),
        new ApiScope("basket", "Basket Service"),
        new ApiScope("webhooks", "Webhooks registration Service"),
    };
}

Diese Methode gibt an, dass IdentityServer die Bestellungen und Warenkorb-APIs schützen soll. Daher sind von IdentityServer verwaltete Zugriffstoken erforderlich, wenn Sie diese APIs aufrufen. Weitere Informationen zum ApiResource-Typ finden Sie unter API-Ressource in der IdentityServer-Dokumentation.

Konfigurieren von Identitätsressourcen

Beim Konfigurieren von Identitätsressourcen erwartet die AddInMemoryIdentityResources-Methode eine IEnumerable<IdentityResource>-Sammlung. Identitätsressourcen sind Daten wie Benutzer-IDs, Namen oder E-Mail-Adressen. Jede Identitätsressource hat einen eindeutigen Namen, und ihr können beliebige Anspruchstypen zugewiesen werden, die im Identitätstoken für den oder die Benutzer*in enthalten sind. Das folgende Codebeispiel zeigt die GetResources-Methode, die diese Sammlung in der eShop-Referenzanwendung bereitstellt:

public static IEnumerable<IdentityResource> GetResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile()
    };
}

Die OpenID Connect-Spezifikation gibt einige Standardidentitätsressourcen an. Die Mindestanforderung ist, dass eine eindeutige Benutzer-ID ausgegeben werden kann. Hierfür wird die Identitätsressource IdentityResources.OpenId verfügbar gemacht.

Hinweis

Die IdentityResources-Klasse unterstützt alle Bereiche, die in der OpenID Connect-Spezifikation definiert sind (OpenID, E-Mail, Profil, Telefon und Adresse).

IdentityServer unterstützt auch das Definieren benutzerdefinierter Identitätsressourcen. Weitere Informationen finden Sie unter Definieren von benutzerdefinierten Identitätsressourcen in der IdentityServer-Dokumentation. Weitere Informationen zum IdentityResource-Typ finden Sie unter IdentityResource in der IdentityServer-Dokumentation.

Konfigurieren von Clients

Clients sind Anwendungen, die Token von IdentityServer anfordern können. In der Regel müssen mindestens die folgenden Einstellungen für jeden Client definiert werden:

  • Eine eindeutige Client-ID
  • Die zulässigen Interaktionen mit dem Tokendienst (auch als Gewährungstyp bezeichnet)
  • Der Speicherort, an den Identitäts- und Zugriffstoken gesendet werden (auch als Umleitungs-URI bezeichnet)
  • Eine Liste der Ressourcen, auf die der Client Zugriff hat (auch als Bereiche bezeichnet)

Beim Konfigurieren von Clients erwartet die AddInMemoryClients-Methode eine IEnumerable<Client>-Sammlung. Das folgende Codebeispiel zeigt die Konfiguration für die Multi-Plattform-App „eShop“ in der GetClients -Methode, die diese Sammlung in der eShop-Referenzanwendung bereitstellt:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        // Omitted for brevity
        new Client
        {
            ClientId = "maui",
            ClientName = "eShop MAUI OpenId Client",
            AllowedGrantTypes = GrantTypes.Code,                    
            //Used to retrieve the access token on the back channel.
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { configuration["MauiCallback"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{configuration["MauiCallback"]}/Account/Redirecting" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket",
                "mobileshoppingagg",
                "webhooks"
            },
            //Allow requesting refresh tokens for long lived API access
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true,
            AlwaysIncludeUserClaimsInIdToken = true,
            AccessTokenLifetime = 60 * 60 * 2, // 2 hours
            IdentityTokenLifetime = 60 * 60 * 2 // 2 hours
        }
    };
}

Diese Konfiguration gibt die Daten für die folgenden Eigenschaften an:

Eigenschaft BESCHREIBUNG
ClientId Eine eindeutige ID für den Client
ClientName Der Clientanzeigename, der für die Protokollierung und den Zustimmungsbildschirm verwendet wird
AllowedGrantTypes Diese Eigenschaft gibt an, wie ein Client mit IdentityServer interagieren möchte. Weitere Informationen finden Sie unter Konfigurieren des Authentifizierungsflows.
ClientSecrets Diese Eigenschaft gibt die Anmeldeinformationen des geheimen Clientschlüssels an, die beim Anfordern von Token vom Tokenendpunkt verwendet werden.
RedirectUris Diese Eigenschaft gibt die zulässigen URIs an, an die Token oder Autorisierungscodes zurückgegeben werden sollen.
RequireConsent Diese Eigenschaft gibt an, ob ein Zustimmungsbildschirm erforderlich ist.
RequirePkce Diese Eigenschaft gibt an, ob Clients, die einen Autorisierungscode verwenden, einen Prüfschlüssel senden müssen.
PostLogoutRedirectUris Diese Eigenschaft gibt die zulässigen URIs an, an die nach der Abmeldung umgeleitet werden soll.
AllowedCorsOrigins Diese Eigenschaft gibt den Ursprung des Clients an, damit IdentityServer ursprungsübergreifende Aufrufe vom Ursprung zulassen kann.
AllowedScopes Diese Eigenschaft gibt die Ressourcen an, auf die der Client Zugriff hat. Standardmäßig hat ein Client keinen Zugriff auf Ressourcen.
AllowOfflineAccess Diese Eigenschaft gibt an, ob der Client Aktualisierungstoken anfordern kann.
AllowAccessTokensViaBrowser Gibt an, ob der Client Zugriffstoken aus einem Browserfenster empfangen kann.
AlwaysIncludeUserClaimsInIdToken Gibt an, dass die Benutzeransprüche immer dem ID-Token hinzugefügt werden. Standardmäßig müssen diese mithilfe des userinfo-Endpunkts abgerufen werden.
AccessTokenLifetime Gibt die Lebensdauer des Zugriffstokens in Sekunden an.
IdentityTokenLifetime Gibt die Lebensdauer des Identitätstokens in Sekunden an.

Konfigurieren des Authentifizierungsflows

Der Authentifizierungsflow zwischen einem Client und IdentityServer kann konfiguriert werden, indem die Gewährungstypen in der Client.AllowedGrantTypes-Eigenschaft angegeben werden. Die OpenID Connect- und OAuth 2.0-Spezifikationen definieren mehrere Authentifizierungsflows, einschließlich:

Authentifizierungsablauf BESCHREIBUNG
Implizit Dieser Flow ist für browserbasierte Anwendungen optimiert und sollte entweder nur für benutzerspezifische Authentifizierungsanforderungen oder für Authentifizierungs- und Zugriffstokenanforderungen verwendet werden. Alle Token werden über den Browser übertragen, sodass erweiterte Features wie Aktualisierungstoken nicht zulässig sind.
Authorization code (Autorisierungscode) Dieser Flow ermöglicht das Abrufen von Token in einem Backchannel statt im Frontchannel des Browsers und unterstützt gleichzeitig die Clientauthentifizierung.
Hybrid Dieser Flow ist eine Kombination aus den impliziten und Autorisierungscode-Gewährungstypen. Das Identitätstoken wird über den Browserkanal übertragen und enthält die signierte Protokollantwort und andere Artefakte wie den Autorisierungscode. Nach erfolgreicher Validierung der Antwort sollte der Backchannel verwendet werden, um das Zugriffs- und Aktualisierungstoken abzurufen.

Tipp

Erwägen Sie die Verwendung des Hybridauthentifizierungsflows. Der Hybridauthentifizierungsflow entschärft verschiedene Angriffe auf Browserkanal und ist der empfohlene Flow für native Anwendungen, die Zugriffstoken (und möglicherweise Aktualisierungstoken) abrufen möchten.

Weitere Informationen zu Authentifizierungsflows finden Sie unter Gewährungstypen in der IdentityServer-Dokumentation.

Durchführen der Authentifizierung

Damit IdentityServer im Namen von Benutzer*innen Token ausstellen kann, muss sich der oder die Benutzer*in bei IdentityServer anmelden. IdentityServer hat jedoch keine Benutzeroberfläche oder Datenbank für die Authentifizierung. Daher wird in der Referenzanwendung „eShop“ ASP.NET Core Identity für diesen Zweck verwendet.

Die Multi-Plattform-App „eShop“ authentifiziert sich bei IdentityServer mit dem Hybridauthentifizierungsflow, der im folgenden Diagramm veranschaulicht wird.

Allgemeine Übersicht über den Anmeldeprozess

Eine Anmeldeanforderung wird an <base endpoint>:5105/connect/authorize gesendet. Nach erfolgreicher Authentifizierung gibt IdentityServer eine Authentifizierungsantwort zurück, die einen Autorisierungscode und ein Identitätstoken enthält. Der Autorisierungscode wird an <base endpoint>:5105/connect/tokengesendet, und die Antwort enthält Zugriffs-, Identitäts- und Aktualisierungstoken.

Die Multi-Plattform-App „eShop“ meldet sich von IdentityServer ab, indem sie eine Anforderung mit zusätzlichen Parametern an <base endpoint>:5105/connect/endsession sendet. Nach der Abmeldung antwortet IdentityServer, indem ein Umleitungs-URI an die Multi-Plattform-App gesendet wird. Das folgende Diagramm veranschaulicht diesen Ablauf:

Allgemeine Übersicht über den Abmeldeprozess

In der Multi-Plattform-App „eShop“ erfolgt die Kommunikation mit IdentityServer über die IdentityService-Klasse, die die IIdentityService-Schnittstelle implementiert. Diese Schnittstelle gibt an, dass eine implementierende Klasse die folgenden Methoden SignInAsync, SignOutAsync, GetUserInfoAsync und GetAuthTokenAsync bereitstellen muss.

Anmelden

Wenn Benutzer*innen unter LoginView auf die Schaltfläche LOGIN tippen, wird der SignInCommand-Befehl der Klasse LoginViewModel ausgeführt, wodurch wiederum die Methode SignInAsync ausgeführt wird. Im folgenden Codebeispiel wird diese Methode veranschaulicht:

[RelayCommand]
private async Task SignInAsync()
{
    await IsBusyFor(
        async () =>
        {
            var loginSuccess = await _appEnvironmentService.IdentityService.SignInAsync();

            if (loginSuccess)
            {
                await NavigationService.NavigateToAsync("//Main/Catalog");
            }
        });
}

Diese Methode ruft die SignInAsync-Methode in der IdentityService-Klasse auf, wie im folgenden Codebeispiel zu sehen ist:

public async Task<bool> SignInAsync()
{
    var response = await GetClient().LoginAsync(new LoginRequest()).ConfigureAwait(false);

    if (response.IsError)
    {
        return false;
    }

    await _settingsService
        .SetUserTokenAsync(
            new UserToken
            {
                AccessToken = response.AccessToken,
                IdToken = response.IdentityToken,
                RefreshToken = response.RefreshToken,
                ExpiresAt = response.AccessTokenExpiration
            })
        .ConfigureAwait(false);

    return !response.IsError;
}

Die IdentityService verwendet OidcClient, der mit dem IdentityModel.OidcClient-NuGet-Paket bereitgestellt wurde. Dieser Client zeigt die Authentifizierungswebansicht für Benutzer*innen in der Anwendung an und erfasst das Authentifizierungsergebnis. Der Client stellt eine Verbindung zu dem URI für den Autorisierungsendpunkt des Identitätsservers mit den erforderlichen Parametern her. Der Autorisierungsendpunkt befindet sich unter /connect/authorize an Port 5105 des Basisendpunkts, der als Benutzereinstellung verfügbar gemacht wird. Weitere Informationen zu Benutzereinstellungen finden Sie unter Konfigurationsverwaltung.

Hinweis

Die Angriffsfläche der Multi-Plattform-App „eShop“ wird reduziert, indem die PKCE-Erweiterung (Proof Key for Code Exchange) in OAuth implementiert wird. PKCE verhindert die Verwendung des Autorisierungscodes, falls dieser abgefangen wird. Hierfür generiert der Client einen geheimen Prüfmechanismus, dessen Hash an die Autorisierungsanforderung übergeben wird und der beim Einlösen des Autorisierungscodes ungehasht angezeigt wird. Weitere Informationen zu PKCE finden Sie unter Proof Key for Code Exchange durch öffentliche OAuth-Clients auf der Website der Internet Engineering Task Force.

Anmeldeseite, die von WebView angezeigt wird

Wenn der Tokenendpunkt gültige Authentifizierungsinformationen, einen gültigen Autorisierungscode und einen PKCE-Geheimnisprüfmechanismus empfängt, antwortet er mit einem Zugriffstoken, Identitätstoken und Aktualisierungstoken. Das Zugriffstoken (das den Zugriff auf API-Ressourcen ermöglicht) und das Identitätstoken werden als Anwendungseinstellungen gespeichert, und die Seitennavigation wird ausgeführt. Gesamtauswirkung auf die Multi-Plattform-App „eShop“: Sofern Benutzer sich erfolgreich bei IdentityServer authentifizieren können, werden sie zur //Main/Catalog-Route weitergeleitet, die ein TabbedPage-Element ist, das CatalogView als ausgewählte Registerkarte anzeigt.

Weitere Informationen zur Seitennavigation finden Sie unter Navigation. Weitere Informationen dazu, wie eine ViewModel-Methode durch die WebView-Navigation ausgeführt wird, finden Sie unter Auslösen der Navigation durch Verhaltensweisen. Weitere Informationen zu Anwendungseinstellungen finden Sie unter Konfigurationsverwaltung.

Hinweis

eShop ermöglicht auch eine Pseudoanmeldung, wenn die App für die Verwendung von Pseudodiensten in SettingsView konfiguriert ist. In diesem Modus kommuniziert die App nicht mit IdentityServer, sondern ermöglicht es Benutzer*innen, sich mit beliebigen Anmeldeinformationen anzumelden.

Abmelden

Wenn Benutzer*innen unter ProfileView auf die Schaltfläche LOG OUT tippen, wird der LogoutCommand-Befehl der Klasse ProfileViewModel ausgeführt, wodurch die Methode LogoutAsync ausgeführt wird. Diese Methode führt die Seitennavigation zur Seite LoginView aus und übergibt einen Logout-Abfrageparameter, der auf true festgelegt ist.

Dieser Parameter wird in der ApplyQueryAttributes-Methode ausgewertet. Wenn der Logout-Parameter mit einem true-Wert vorhanden ist, wird die PerformLogoutAsync-Methode der LoginViewModel-Klasse ausgeführt, die im folgenden Codebeispiel dargestellt wird:

private async Task PerformLogoutAsync()
{
    await _appEnvironmentService.IdentityService.SignOutAsync();

    _settingsService.UseFakeLocation = false;

    UserName.Value = string.Empty;
    Password.Value = string.Empty;
}

Diese Methode ruft die SignOutAsync-Methode in der Klasse „IdentityService“ auf, die den OidcClient aufruft, um die Sitzung des Benutzers zu beenden und alle gespeicherten Benutzertoken zu löschen. Weitere Informationen zu Anwendungseinstellungen finden Sie unter Konfigurationsverwaltung. Die SignOutAsync-Methode wird in folgendem Codebeispiel veranschaulicht:

public async Task<bool> SignOutAsync()
{
    var response = await GetClient().LogoutAsync(new LogoutRequest()).ConfigureAwait(false);

    if (response.IsError)
    {
        return false;
    }

    await _settingsService.SetUserTokenAsync(default);

    return !response.IsError;
}

Diese Methode verwendet die OidcClient, um den URI mit den erforderlichen Parametern an den Endsitzungsendpunkt des Identitätsservers aufzurufen. Der Endpunkt zum Beenden der Sitzung befindet sich unter /connect/endsession an Port 5105 des Basisendpunkts, der als Benutzereinstellung verfügbar gemacht wird. Sobald sich der*die Benutzer*in erfolgreich abgemeldet hat, wird ihm*ihr LoginView angezeigt, und alle gespeicherten Benutzerinformationen werden gelöscht.

Weitere Informationen zur Seitennavigation finden Sie unter Navigation. Weitere Informationen dazu, wie eine ViewModel-Methode durch die WebView-Navigation ausgeführt wird, finden Sie unter Auslösen der Navigation durch Verhaltensweisen. Weitere Informationen zu Anwendungseinstellungen finden Sie unter Konfigurationsverwaltung.

Hinweis

eShop ermöglicht auch eine Pseudoabmeldung, wenn die App für die Verwendung von Pseudodiensten in SettingsView konfiguriert ist. In diesem Modus kommuniziert die App nicht mit IdentityServer und löscht stattdessen alle gespeicherten Token aus den Anwendungseinstellungen.

Authorization

Nach der Authentifizierung müssen ASP.NET Core-Web-APIs häufig den Zugriff autorisieren, sodass ein Dienst APIs für einige authentifizierte Benutzer*innen verfügbar machen kann, aber nicht für alle.

Das Einschränken des Zugriffs auf eine ASP.NET Core-Route kann erreicht werden, indem ein Authorize-Attribut auf einen Controller oder eine Aktion angewendet wird. Hierdurch wird der Zugriff auf den Controller oder die Aktion wie im folgenden Codebeispiel dargestellt auf authentifizierte Benutzer*innen beschränkt:

[Authorize]
public sealed class BasketController : Controller
{
    // Omitted for brevity
}

Wenn ein*e nicht autorisierte*r Benutzer*in versucht, auf einen Controller oder eine Aktion zuzugreifen, die mit dem Authorize-Attribut gekennzeichnet ist, gibt das API-Framework den HTTP-Statuscode 401 (unauthorized) zurück.

Hinweis

Parameter können im Authorize-Attribut angegeben werden, um eine API auf bestimmte Benutzer*innen zu beschränken. Weitere Informationen finden Sie unter ASP.NET Core-Dokumentation: Autorisierung.

IdentityServer kann in den Autorisierungsworkflow integriert werden, sodass die Zugriffstoken Steuerungsautorisierung bereitstellen. Dieser Ansatz wird im folgenden Diagramm veranschaulicht.

Autorisierung durch Zugriffstoken

Die Multi-Plattform-App „eShop“ kommuniziert mit dem Identitätsmicroservice und fordert während des Authentifizierungsprozesses ein Zugriffstoken an. Das Zugriffstoken wird dann an die APIs weitergeleitet, die von den Bestell- und Warenkorbmicroservices im Rahmen der Zugriffsanforderungen verfügbar gemacht werden. Zugriffstoken enthalten Informationen über den Client und den oder die Benutzer*in. APIs verwenden diese Informationen dann, um den Zugriff auf ihre Daten zu autorisieren. Weitere Informationen zum Konfigurieren von IdentityServer zum Schutz von APIs finden Sie unter Konfigurieren von API-Ressourcen.

Konfigurieren von IdentityServer für die Autorisierung

Um die Autorisierung mit IdentityServer durchzuführen, muss die zugehörige Autorisierungsmiddleware der HTTP-Anforderungspipeline der Webanwendung hinzugefügt werden. Die Middleware wird in der AddDefaultAuthentication-Erweiterungsmethode hinzugefügt, die von der AddApplicationServices-Methode in der Klasse „Program“ aufgerufen wird und im folgenden Codebeispiel aus der eShop-Referenzanwendung veranschaulicht wird:

public static IServiceCollection AddDefaultAuthentication(this IHostApplicationBuilder builder)
{
    var services = builder.Services;
    var configuration = builder.Configuration;

    var identitySection = configuration.GetSection("Identity");

    if (!identitySection.Exists())
    {
        // No identity section, so no authentication
        return services;
    }

    // prevent from mapping "sub" claim to nameidentifier.
    JsonWebTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");

    services.AddAuthentication().AddJwtBearer(options =>
    {
        var identityUrl = identitySection.GetRequiredValue("Url");
        var audience = identitySection.GetRequiredValue("Audience");

        options.Authority = identityUrl;
        options.RequireHttpsMetadata = false;
        options.Audience = audience;
        options.TokenValidationParameters.ValidIssuers = [identityUrl];
        options.TokenValidationParameters.ValidateAudience = false;
    });

    services.AddAuthorization();

    return services;
}

Diese Methode stellt sicher, dass nur mit einem gültigen Zugriffstoken auf die API zugegriffen werden kann. Die Middleware überprüft das eingehende Token, um sicherzustellen, dass es von einem vertrauenswürdigen Aussteller gesendet wird und für die empfangende API gültig ist. Daher wird beim Navigieren zum Bestell- oder Warenkorbcontroller der HTTP-Statuscode 401 (unauthorized) zurückgegeben, der angibt, dass ein Zugriffstoken erforderlich ist.

Senden von Zugriffsanforderungen an APIs

Beim Senden von Anforderungen an die Bestell- und Warenkorbmicroservices muss das Zugriffstoken, das während des Authentifizierungsprozesses von IdentityServer abgerufen wurde, in die Anforderung eingeschlossen werden. Dieser Vorgang wird im folgenden Codebeispiel gezeigt:

public async Task CreateOrderAsync(Models.Orders.Order newOrder)
{
    var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);

    if (string.IsNullOrEmpty(authToken))
    {
        return;
    }

    var uri = $"{UriHelper.CombineUri(_settingsService.GatewayOrdersEndpointBase, ApiUrlBase)}?api-version=1.0";

    var success = await _requestProvider.PostAsync(uri, newOrder, authToken, "x-requestid").ConfigureAwait(false);
}

Das Zugriffstoken wird mit der IIdentityService-Implementierung gespeichert und kann mithilfe der GetAuthTokenAsync-Methode abgerufen werden.

Ebenso muss das Zugriffstoken beim Senden von Daten an eine geschützte IdentityServer-API eingeschlossen werden, wie im folgenden Codebeispiel zu sehen ist:

public async Task ClearBasketAsync()
{
    var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);

    if (string.IsNullOrEmpty(authToken))
    {
        return;
    }

    await GetBasketClient().DeleteBasketAsync(new DeleteBasketRequest(), CreateAuthenticationHeaders(authToken))
        .ConfigureAwait(false);
}

Das Zugriffstoken wird aus IIdentityService abgerufen und in den Aufruf der ClearBasketAsync-Methode in der Klasse „BasketService“ eingeschlossen.

Die RequestProvider-Klasse in der Multi-Plattform-App „eShop“ verwendet die HttpClient-Klasse, um Anforderungen an die RESTful-APIs zu senden, die von der eShop-Referenzanwendung verfügbar gemacht werden. Wenn Sie Anforderungen an die Bestell- und Warenkorb-APIs senden, die eine Autorisierung erfordern, muss ein gültiges Zugriffstoken in die Anforderung eingeschlossen werden. Fügen Sie hierzu wie im folgenden Codebeispiel das Zugriffstoken in die Header der HttpClient-Instanz ein:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

Die DefaultRequestHeaders-Eigenschaft der HttpClient-Klasse macht die Header verfügbar, die mit jeder Anforderung gesendet werden, und das Zugriffstoken wird dem Header Authorization mit dem Präfix Bearer hinzugefügt. Wenn die Anforderung an eine RESTful-API gesendet wird, wird der Wert des Authorization-Headers extrahiert und überprüft, um sicherzustellen, dass er von einem vertrauenswürdigen Aussteller gesendet. Dann wird er verwendet, um zu ermitteln, ob der oder die Benutzer*in über die Berechtigung zum Aufrufen der empfangenden API verfügt.

Weitere Informationen dazu, wie die Multi-Plattform-App „eShop“ Webanforderungen sendet, finden Sie unter Zugreifen auf Remotedaten.

Zusammenfassung

Es gibt viele Ansätze für die Integration von Authentifizierung und Autorisierung in eine .NET MAUI-App, die mit einer ASP.NET-Webanwendung kommuniziert. Die Multi-Plattform-App „eShop“ führt die Authentifizierung und Autorisierung mit einem Microservice für containerisierte Identitäten durch, der IdentityServer verwendet. IdentityServer ist ein Open-Source-Framework mit OpenID Connect und OAuth 2.0 für ASP.NET Core, das mit ASP.NET Core Identity integriert werden kann, um die Bearertokenauthentifizierung durchzuführen.

Die Multi-Plattform-App fordert mehrere Sicherheitstoken von IdentityServer an, um eine*n Benutzer*in zu authentifizieren oder auf eine Ressource zuzugreifen. Beim Zugriff auf eine Ressource muss ein Zugriffstoken in die Anforderung an APIs eingeschlossen werden, die eine Autorisierung erfordern. Die Middleware von IdentityServer überprüft eingehende Zugriffstoken, um sicherzustellen, dass diese von einem vertrauenswürdigen Aussteller gesendet werden und für die empfangende API gültig sind.