Authentifizierung und Autorisierung

Hinweis

Dieses eBook wurde im Frühjahr 2017 veröffentlicht und wurde seitdem nicht aktualisiert. Es gibt viel in dem Buch, das wieder Standard wertvoll ist, aber einige der Materialien sind veraltet.

Die Authentifizierung ist der Prozess des Abrufens von Identifikationsanmeldeinformationen wie Name und Kennwort von einem Benutzer und das Überprüfen dieser Anmeldeinformationen für eine Autorität. Wenn die Anmeldeinformationen gültig sind, wird die Entität, die die Anmeldeinformationen übermittelt hat, als authentifizierte Identität betrachtet. Nachdem eine Identität authentifiziert wurde, bestimmt ein Autorisierungsprozess, ob diese Identität Zugriff auf eine bestimmte Ressource hat.

Es gibt viele Ansätze zur Integration von Authentifizierung und Autorisierung in eine Xamarin.Forms App, die mit einer ASP.NET MVC-Webanwendung kommuniziert, einschließlich der Verwendung von ASP.NET Core Identity, externen Authentifizierungsanbietern wie Microsoft, Google, Facebook oder Twitter und Authentifizierungs-Middleware. Die mobile eShopOnContainers-App führt Authentifizierung und Autorisierung mit einem containerisierten Identitäts-Microservice durch, der IdentityServer 4 verwendet. Die mobile App fordert Sicherheitstoken von IdentityServer an, entweder für die Authentifizierung eines Benutzers oder für den Zugriff auf eine Ressource. Damit IdentityServer Token im Namen eines Benutzers ausstellen kann, muss sich der Benutzer bei IdentityServer anmelden. IdentityServer hat jedoch keine Benutzeroberfläche oder Datenbank für die Authentifizierung. Daher wird in der Referenzanwendung „eShopOnContainers“ ASP.NET Core Identity für diesen Zweck verwendet.

Authentifizierung

Die Authentifizierung ist erforderlich, wenn eine Anwendung die Identität des aktuellen Benutzers 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 EntityFramework-Speicher, obwohl benutzerdefinierte Speicher oder Pakete von Drittanbietern verwendet werden können, um Identitätsinformationen in Azure Storage, Azure Cosmos DB oder anderen Speicherorten zu speichern.

Für Authentifizierungsszenarien, die einen lokalen Benutzerdatenspeicher verwenden und Identitätsinformationen zwischen Anforderungen über Cookies beibehalten (wie in ASP.NET MVC-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. Eine ASP.NET Core-Webanwendung, die RESTful-Endpunkte verfügbar macht, auf die über eine mobile App zugegriffen wird, muss 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 mobilen App vorgenommen wurden.

Ausstellen von Bearertoken mit IdentityServer 4

IdentityServer 4 ist ein Open Source OpenID-Verbinden- und OAuth 2.0-Framework für ASP.NET Core, das für viele Authentifizierungs- und Autorisierungsszenarien verwendet werden kann, einschließlich des Ausstellens von Sicherheitstoken für lokale ASP.NET Core Identity-Benutzer.

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.

Die Kombination aus OpenID Verbinden und OAuth 2.0 kombiniert die beiden grundlegenden Sicherheitsaspekte des Authentifizierungs- und API-Zugriffs, und IdentityServer 4 ist eine Implementierung dieser Protokolle.

In Anwendungen, die eine direkte Client-zu-Microservice-Kommunikation verwenden, z. B. die eShopOnContainers-Referenzanwendung, kann ein dedizierter Authentifizierungs-Microservice verwendet werden, der als Sicherheitstokendienst (Security Token Service, STS) fungiert, wie in Abbildung 9-1 dargestellt. Weitere Informationen zur direkten Client-zu-Microservice-Kommunikation finden Sie unter Communication Between Client and Microservices.

Authentication by a dedicated authentication microservice

Abbildung 9-1: Authentifizierung durch einen dedizierten Authentifizierungs-Microservice

Die mobile eShopOnContainers-App kommuniziert mit dem Identitäts-Microservice, der IdentityServer 4 zum Durchführen der Authentifizierung und Zugriffssteuerung für APIs verwendet. Daher fordert die mobile App Token von IdentityServer an, entweder für die Authentifizierung eines Benutzers oder für den Zugriff auf eine Ressource:

  • Die Authentifizierung von Benutzern mit IdentityServer wird durch die mobile App erreicht, die ein Identitätstoken anfordert, das das Ergebnis eines Authentifizierungsprozesses darstellt. Es enthält mindestens einen Bezeichner für den Benutzer und Informationen dazu, wie und wann der Benutzer authentifiziert wurde. Sie kann auch zusätzliche Identitätsdaten enthalten.
  • Der Zugriff auf eine Ressource mit IdentityServer wird durch die mobile App erreicht, 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 Benutzer (sofern vorhanden). APIs verwenden diese Informationen dann, um den Zugriff auf ihre Daten zu autorisieren.

Hinweis

Ein Client muss mit IdentityServer registriert werden, bevor er Token anfordern kann.

Hinzufügen von IdentityServer zu einer Webanwendung

Damit eine ASP.NET Core-Webanwendung IdentityServer 4 verwenden kann, muss sie der Visual Studio-Projektmappe der Webanwendung hinzugefügt werden. Weitere Informationen finden Sie in der IdentityServer-Dokumentation im Überblick .

Sobald IdentityServer in der Visual Studio-Lösung der Webanwendung enthalten ist, muss sie der HTTP-Anforderungsverarbeitungspipeline der Webanwendung hinzugefügt werden, damit sie Anforderungen an OpenID-Verbinden- und OAuth 2.0-Endpunkte bereitstellen kann. Verwenden Sie hierfür wie im folgenden Codebeispiel veranschaulicht die Configure-Methode in der Startup-Klasse der Webanwendung:

public void Configure(  
    IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{  
    ...  
    app.UseIdentity();  
    ...  
}

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 sollte in der Methode in der ConfigureServices Klasse der Webanwendung Startup durch Aufrufen der services.AddIdentityServer Methode konfiguriert werden, wie im folgenden Codebeispiel aus der eShopOnContainers-Referenzanwendung veranschaulicht:

public void ConfigureServices(IServiceCollection services)  
{  
    ...  
    services.AddIdentityServer(x => x.IssuerUri = "null")  
        .AddSigningCredential(Certificate.Get())                 
        .AddAspNetIdentity<ApplicationUser>()  
        .AddConfigurationStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .AddOperationalStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .Services.AddTransient<IProfileService, ProfileService>();  
}

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 4-Konfiguration dynamisch. Die APIs von IdentityServer 4 ermöglichen das Konfigurieren von IdentityServer über eine In-Memory-Liste mit Konfigurationsobjekten. In der Referenzanwendung „eShopOnContainers“ 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 eShopOnContainers-Referenzanwendung bereitstellt:

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

Diese Methode gibt an, dass IdentityServer die Bestellungen und Warenkorb-APIs schützen soll. Daher sind verwaltete Identitätsserver-Zugriffstoken erforderlich, wenn Aufrufe an diese APIs getätigt werden. Weitere Informationen zum ApiResource-Typ finden Sie unter API-Ressource in der IdentityServer 4-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 beliebige Anspruchstypen können ihm zugewiesen werden, die dann im Identitätstoken für den Benutzer enthalten sein. Das folgende Codebeispiel zeigt die GetResources-Methode, die diese Sammlung in der eShopOnContainers-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 in der OpenID-Verbinden Spezifikation definierten Bereiche (OpenID, E-Mail, Profil, Telefon und Adresse).

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

Configuring Clients (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 mobile eShopOnContainers-App in der GetClients Methode, die diese Auflistung in der Referenzanwendung "eShopOnContainers" bereitstellt:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        ...
        new Client
        {
            ClientId = "xamarin",
            ClientName = "eShop Xamarin OpenId Client",
            AllowedGrantTypes = GrantTypes.Hybrid,
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { clientsUrl["Xamarin"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
            AllowedCorsOrigins = { "http://eshopxamarin" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket"
            },
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true
        },
        ...
    };
}

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

  • ClientId: Eine eindeutige ID für den Client.
  • ClientName: Der Clientanzeigename, der für die Protokollierung und den Zustimmungsbildschirm verwendet wird.
  • AllowedGrantTypes: Gibt an, wie ein Client mit IdentityServer interagieren möchte. Weitere Informationen finden Sie unter Konfigurieren des Authentifizierungsflusses.
  • ClientSecrets: Gibt die geheimen Clientschlüsselanmeldeinformationen an, die beim Anfordern von Token vom Tokenendpunkt verwendet werden.
  • RedirectUris: Gibt die zulässigen URIs an, an die Token oder Autorisierungscodes zurückgegeben werden sollen.
  • RequireConsent: Gibt an, ob ein Zustimmungsbildschirm erforderlich ist.
  • RequirePkce: Gibt an, ob Clients, die einen Autorisierungscode verwenden, einen Proof Key senden müssen.
  • PostLogoutRedirectUris: Gibt die zulässigen URIs an, an die nach dem Abmelden umgeleitet werden soll.
  • AllowedCorsOrigins: Gibt den Ursprung des Clients an, damit IdentityServer ursprungsübergreifende Aufrufe vom Ursprung zulassen kann.
  • AllowedScopes: Gibt die Ressourcen an, auf die der Client zugreifen kann. Standardmäßig hat ein Client keinen Zugriff auf Ressourcen.
  • AllowOfflineAccess: Gibt an, ob der Client Aktualisierungstoken anfordern kann.

Konfigurieren des Authentifizierungsflusses

Der Authentifizierungsflow zwischen einem Client und IdentityServer kann konfiguriert werden, indem die Gewährungstypen in der Client.AllowedGrantTypes-Eigenschaft angegeben werden. Die OpenID-Verbinden- und OAuth 2.0-Spezifikationen definieren eine Reihe von Authentifizierungsflüssen, darunter:

  • Implizite. 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.
  • 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 zusammen mit anderen Artefakten wie dem Autorisierungscode. Nach erfolgreicher Überprüfung der Antwort sollte der Zurückkanal verwendet werden, um das Zugriffs- und Aktualisierungstoken abzurufen.

Tipp

Verwenden Sie den Hybridauthentifizierungsfluss. 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 4-Dokumentation.

Durchführen der Authentifizierung

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

Die mobile eShopOnContainers-App authentifiziert sich mit IdentityServer mit dem Hybridauthentifizierungsfluss, der in Abbildung 9-2 dargestellt wird.

High-level overview of the sign-in process

Abbildung 9-2: Allgemeine Übersicht über den Anmeldevorgang

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

Die mobile eShopOnContainers-App meldet sich von IdentityServer ab, indem sie eine Anforderung mit zusätzlichen Parametern sendet <base endpoint>:5105/connect/endsession. Nachdem die Abmeldung erfolgt, antwortet IdentityServer, indem ein Umleitungs-URI nach dem Abmelden zurück an die mobile App gesendet wird. Abbildung 9-3 veranschaulicht diesen Prozess.

High-level overview of the sign-out process

Abbildung 9-3: Allgemeine Übersicht über den Abmeldungsprozess

In der mobilen eShopOnContainers-App wird die Kommunikation mit IdentityServer von der IdentityService Klasse ausgeführt, die die IIdentityService Schnittstelle implementiert. Diese Schnittstelle gibt an, dass eine implementierende Klasse die folgenden Methoden CreateAuthorizationRequest, CreateLogoutRequest und GetTokenAsync bereitstellen muss.

Anmelden

Wenn der Benutzer auf die Schaltfläche "LOGIN " auf der LoginViewSchaltfläche tippt, wird die SignInCommand Klasse LoginViewModel ausgeführt, die wiederum die SignInAsync Methode ausführt. Im folgenden Codebeispiel wird diese Methode veranschaulicht:

private async Task SignInAsync()  
{  
    ...  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    IsLogin = true;  
    ...  
}

Diese Methode ruft die CreateAuthorizationRequest Methode in der IdentityService Klasse auf, die im folgenden Codebeispiel dargestellt wird:

public string CreateAuthorizationRequest()
{
    // Create URI to authorization endpoint
    var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint);

    // Dictionary with values for the authorize request
    var dic = new Dictionary<string, string>();
    dic.Add("client_id", GlobalSetting.Instance.ClientId);
    dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); 
    dic.Add("response_type", "code id_token");
    dic.Add("scope", "openid profile basket orders locations marketing offline_access");
    dic.Add("redirect_uri", GlobalSetting.Instance.Callback);
    dic.Add("nonce", Guid.NewGuid().ToString("N"));
    dic.Add("code_challenge", CreateCodeChallenge());
    dic.Add("code_challenge_method", "S256");

    // Add CSRF token to protect against cross-site request forgery attacks.
    var currentCSRFToken = Guid.NewGuid().ToString("N");
    dic.Add("state", currentCSRFToken);

    var authorizeUri = authorizeRequest.Create(dic); 
    return authorizeUri;
}

Diese Methode erstellt den URI für den Autorisierungsendpunkt von IdentityServer mit den erforderlichen Parametern. 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 mobilen eShopOnContainers-App wird durch die Implementierung der Proof Key for Code Exchange (PKCE)-Erweiterung in OAuth reduziert. PKCE schützt den Autorisierungscode vor der Verwendung, wenn er 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.

Der zurückgegebene URI wird in der LoginUrl-Eigenschaft der LoginViewModel-Klasse gespeichert. Wenn die IsLogin Eigenschaft wird true, wird das WebView In-In LoginView sichtbar. Die WebView Daten binden ihre Source Eigenschaft an die LoginUrl Eigenschaft der LoginViewModel Klasse und stellen daher eine Anmeldeanforderung an IdentityServer vor, wenn die LoginUrl Eigenschaft auf den Autorisierungsendpunkt von IdentityServer festgelegt ist. Wenn IdentityServer diese Anforderung empfängt und der Benutzer nicht authentifiziert wird, wird er WebView an die konfigurierte Anmeldeseite umgeleitet, die in Abbildung 9-4 dargestellt wird.

Login page displayed by the WebView

Abbildung 9-4: Anmeldeseite, die von webView angezeigt wird

Sobald die Anmeldung erfolgt ist, wird WebView an einen Rückgabe-URI umgeleitet. Durch die WebView-Navigation wird die NavigateAsync-Methode in der LoginViewModel-Klasse ausgeführt, was im folgenden Codebeispiel gezeigt wird:

private async Task NavigateAsync(string url)  
{  
    ...  
    var authResponse = new AuthorizeResponse(url);  
    if (!string.IsNullOrWhiteSpace(authResponse.Code))  
    {  
        var userToken = await _identityService.GetTokenAsync(authResponse.Code);  
        string accessToken = userToken.AccessToken;  

        if (!string.IsNullOrWhiteSpace(accessToken))  
        {  
            Settings.AuthAccessToken = accessToken;  
            Settings.AuthIdToken = authResponse.IdentityToken;  

            await NavigationService.NavigateToAsync<MainViewModel>();  
            await NavigationService.RemoveLastFromBackStackAsync();  
        }  
    }  
    ...  
}

Diese Methode analysiert die Authentifizierungsantwort, die im Rückgabe-URI enthalten ist, und vorausgesetzt, dass ein gültiger Autorisierungscode vorhanden ist, sendet sie eine Anforderung an den Tokenendpunkt von IdentityServer, das Übergeben des Autorisierungscodes, den geheimen PKCE-Prüfer und andere erforderliche Parameter. Der Tokenendpunkt befindet sich unter /connect/token an Port 5105 des Basisendpunkts, der als Benutzereinstellung verfügbar gemacht wird. Weitere Informationen zu Benutzereinstellungen finden Sie unter Konfigurationsverwaltung.

Tipp

Überprüfen der Rückgabe-URIs. Obwohl die mobile eShopOnContainers-App den Rückgabe-URI nicht überprüft, empfiehlt es sich, zu überprüfen, ob der Rückgabe-URI auf einen bekannten Speicherort verweist, um Open-Redirect-Angriffe zu verhindern.

Wenn der Tokenendpunkt 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 zulässt) und das Identitätstoken werden dann als Anwendungseinstellungen gespeichert, und die Seitennavigation wird ausgeführt. Daher ist der Gesamteffekt in der mobilen eShopOnContainers-App: Vorausgesetzt, dass Benutzer sich erfolgreich bei IdentityServer authentifizieren können, werden sie zu der MainView Seite navigiert, die TabbedPage als CatalogView ausgewählte Registerkarte angezeigt wird.

Weitere Informationen zur Seitennavigation finden Sie unter Navigation. Informationen dazu, wie die Navigation bewirkt, dass WebView eine Ansichtsmodellmethode ausgeführt wird, finden Sie unter "Aufrufen der Navigation mithilfe von Verhalten". Informationen zu Anwendungseinstellungen finden Sie unter Configuration Management.

Hinweis

Die eShopOnContainers ermöglichen auch eine simulierte Anmeldung, wenn die App so konfiguriert ist, dass simulierte Dienste in der SettingsViewApp verwendet werden. In diesem Modus kommuniziert die App nicht mit IdentityServer, sondern ermöglicht es dem Benutzer, sich mit anmeldeinformationen anzumelden.

Abmelden

Wenn der Benutzer auf die Schaltfläche "ABMELDEn " in der ProfileViewKlasse tippt, wird die LogoutCommand Klasse ProfileViewModel ausgeführt, wodurch wiederum die LogoutAsync Methode ausgeführt wird. Diese Methode führt die Seitennavigation zur Seite LoginView aus und übergibt eine LogoutParameter-Instanz, deren Parameter auf true festgelegt ist. Weitere Informationen zum Übergeben von Parametern während der Seitennavigation finden Sie unter Übergeben von Parametern während der Navigation.

Wenn eine Ansicht erstellt und zu dieser navigiert wird, wird die InitializeAsync-Methode des zugeordneten Ansichtsmodells ausgeführt, wodurch dann die Logout-Methode der LoginViewModel-Klasse ausgeführt wird. Dieser Ablauf wird im folgenden Codebeispiel veranschaulicht:

private void Logout()  
{  
    var authIdToken = Settings.AuthIdToken;  
    var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);  

    if (!string.IsNullOrEmpty(logoutRequest))  
    {  
        // Logout  
        LoginUrl = logoutRequest;  
    }  
    ...  
}

Diese Methode ruft die CreateLogoutRequest-Methode in der IdentityService-Klasse auf und übergibt das aus den Anwendungseinstellungen abgerufene Identitätstoken als Parameter. Weitere Informationen zu Anwendungseinstellungen finden Sie unter Configuration Management. Die CreateLogoutRequest-Methode wird in folgendem Codebeispiel veranschaulicht:

public string CreateLogoutRequest(string token)  
{  
    ...  
    return string.Format("{0}?id_token_hint={1}&post_logout_redirect_uri={2}",   
        GlobalSetting.Instance.LogoutEndpoint,  
        token,  
        GlobalSetting.Instance.LogoutCallback);  
}

Diese Methode erstellt den URI zum Endpunkt der IdentityServer-Sitzung mit den erforderlichen Parametern. Der Endpunkt zum Beenden der Sitzung befindet sich unter /connect/endsession an Port 5105 des Basisendpunkts, der als Benutzereinstellung verfügbar gemacht wird. Weitere Informationen zu Benutzereinstellungen finden Sie unter Konfigurationsverwaltung.

Der zurückgegebene URI wird in der LoginUrl-Eigenschaft der LoginViewModel-Klasse gespeichert. IsLogin Die Eigenschaft ist truezwar WebViewLoginView sichtbar. Die WebView Daten binden ihre Source Eigenschaft an die LoginUrl Eigenschaft der LoginViewModel Klasse und stellen daher eine Abmeldeanforderung an IdentityServer vor, wenn die LoginUrl Eigenschaft auf den Endpunkt der Endsitzung von IdentityServer festgelegt ist. Wenn IdentityServer diese Anforderung empfängt, sofern der Benutzer angemeldet ist, tritt die Abmeldung auf. Die Authentifizierung wird mit einem Cookie nachverfolgt, das von der Middleware für die Cookieauthentifizierung von ASP.NET Core verwaltet wird. Daher entfernt das Abmelden von IdentityServer das Authentifizierungscookies und sendet einen Umleitungs-URI nach dem Abmelden an den Client zurück.

In der mobilen App wird der WebView Umleitungs-URI nach der Abmeldung umgeleitet. Durch die WebView-Navigation wird die NavigateAsync-Methode in der LoginViewModel-Klasse ausgeführt, was im folgenden Codebeispiel gezeigt wird:

private async Task NavigateAsync(string url)  
{  
    ...  
    Settings.AuthAccessToken = string.Empty;  
    Settings.AuthIdToken = string.Empty;  
    IsLogin = false;  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    ...  
}

Diese Methode löscht sowohl das Identitätstoken als auch das Zugriffstoken aus den Anwendungseinstellungen und legt die IsLogin Eigenschaft auf falsefest, wodurch die WebViewLoginView Seite unsichtbar wird. Schließlich wird die LoginUrl-Eigenschaft auf den URI des Autorisierungsendpunkts von IdentityServer mit den erforderlichen Parametern festgelegt, um die nächste Benutzeranmeldung vorzubereiten.

Weitere Informationen zur Seitennavigation finden Sie unter Navigation. Informationen dazu, wie die Navigation bewirkt, dass WebView eine Ansichtsmodellmethode ausgeführt wird, finden Sie unter "Aufrufen der Navigation mithilfe von Verhalten". Informationen zu Anwendungseinstellungen finden Sie unter Configuration Management.

Hinweis

Die eShopOnContainers ermöglichen auch eine simulierte Abmeldung, wenn die App so konfiguriert ist, dass simulierte Dienste im Einstellungen View verwendet werden. In diesem Modus kommuniziert die App nicht mit IdentityServer und löscht stattdessen alle gespeicherten Token aus den Anwendungseinstellungen.

Autorisierung

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

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

[Authorize]  
public class BasketController : Controller  
{  
    ...  
}

Wenn ein nicht autorisierter Benutzer versucht, auf einen Controller oder eine Aktion zuzugreifen, der mit dem Authorize Attribut gekennzeichnet ist, gibt das MVC-Framework einen HTTP-Statuscode 401 (nicht autorisiert) zurück.

Hinweis

Parameter können für das Authorize Attribut angegeben werden, um eine API auf bestimmte Benutzer einzuschränken. Weitere Informationen finden Sie unter Autorisierung.

IdentityServer kann in den Autorisierungsworkflow integriert werden, sodass die bereitgestellten Zugriffstoken die Autorisierung steuern. Dieser Ansatz ist in Abbildung 9-5 dargestellt.

Authorization by access token

Abbildung 9-5: Autorisierung nach Zugriffstoken

Die mobile eShopOnContainers-App kommuniziert mit dem Identitäts-Microservice und fordert ein Zugriffstoken als Teil des Authentifizierungsprozesses 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 Benutzer. APIs verwenden diese Informationen dann, um den Zugriff auf ihre Daten zu autorisieren. Informationen zum Konfigurieren von IdentityServer zum Schutz von APIs finden Sie unter Konfigurieren von API-Ressourcen.

Konfigurieren von IdentityServer zum Durchführen der 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 ConfigureAuth Methode der Webanwendungsklasse Startup hinzugefügt, die von der Configure Methode aufgerufen wird, und wird im folgenden Codebeispiel aus der eShopOnContainers-Referenzanwendung veranschaulicht:

protected virtual void ConfigureAuth(IApplicationBuilder app)  
{  
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");  
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions  
    {  
        Authority = identityUrl.ToString(),  
        ScopeName = "basket",  
        RequireHttpsMetadata = false  
    });  
} 

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 überprüft, ob das Token gültig ist, um mit der API verwendet zu werden, die es empfängt. Daher gibt das Browsen zum Sortier- oder Korbcontroller einen HTTP-Statuscode 401 (nicht autorisiert) zurück, der angibt, dass ein Zugriffstoken erforderlich ist.

Hinweis

Die Autorisierungsmiddleware von IdentityServer muss der HTTP-Anforderungspipeline der Webanwendung hinzugefügt werden, bevor MVC mit app.UseMvc() oder app.UseMvcWithDefaultRoute() hinzugefügt wird.

Erstellen von Zugriffsanforderungen an APIs

Beim Senden von Anforderungen an die Sortierung und den Korb microservices muss das Zugriffstoken, das während des Authentifizierungsprozesses von IdentityServer abgerufen wird, in die Anforderung aufgenommen werden, wie im folgenden Codebeispiel gezeigt:

var authToken = Settings.AuthAccessToken;  
Order = await _ordersService.GetOrderAsync(Convert.ToInt32(order.OrderNumber), authToken);

Das Zugriffstoken wird als Anwendungseinstellung gespeichert und aus plattformspezifischem Speicher abgerufen und im Aufruf der GetOrderAsync Methode in der OrderService Klasse enthalten.

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

var authToken = Settings.AuthAccessToken;  
await _basketService.UpdateBasketAsync(new CustomerBasket  
{  
    BuyerId = userInfo.UserId,   
    Items = BasketItems.ToList()  
}, authToken);

Das Zugriffstoken wird aus plattformspezifischem Speicher abgerufen und im Aufruf der UpdateBasketAsync Methode in der BasketService Klasse enthalten.

Die RequestProvider Klasse in der mobilen eShopOnContainers-App verwendet die HttpClient Klasse, um Anforderungen an die RESTful-APIs zu stellen, die von der eShopOnContainers-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. Dies wird durch Hinzufügen des Zugriffstokens zu den Headern der HttpClient Instanz erreicht, wie im folgenden Codebeispiel veranschaulicht:

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 sie von einem vertrauenswürdigen Aussteller gesendet wird und verwendet wird, um zu bestimmen, ob der Benutzer über die Berechtigung zum Aufrufen der API verfügt, die sie empfängt.

Weitere Informationen dazu, wie die mobile eShopOnContainers-App Webanforderungen sendet, finden Sie unter "Zugreifen auf Remotedaten".

Zusammenfassung

Es gibt viele Ansätze zum Integrieren von Authentifizierung und Autorisierung in eine Xamarin.Forms App, die mit einer ASP.NET MVC-Webanwendung kommuniziert. Die mobile eShopOnContainers-App führt Authentifizierung und Autorisierung mit einem containerisierten Identitäts-Microservice durch, der IdentityServer 4 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 mobile App fordert Sicherheitstoken von IdentityServer an, entweder für die Authentifizierung eines Benutzers oder für den Zugriff auf eine Ressource. 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 sie von einem vertrauenswürdigen Aussteller gesendet werden und dass sie mit der API verwendet werden, die sie empfängt.