Uwierzytelnianie i autoryzacja

Uwaga

Ta książka elektroniczna została opublikowana wiosną 2017 r. i od tego czasu nie została zaktualizowana. Jest wiele w książce, która pozostaje cenna, ale niektóre z materiałów są przestarzałe.

Uwierzytelnianie to proces uzyskiwania poświadczeń identyfikacji, takich jak nazwa i hasło od użytkownika, oraz weryfikowanie tych poświadczeń względem urzędu. Jeśli poświadczenia są prawidłowe, jednostka, która przesłała poświadczenia, jest traktowana jako uwierzytelniona tożsamość. Po uwierzytelnieniu tożsamości proces autoryzacji określa, czy ta tożsamość ma dostęp do danego zasobu.

Istnieje wiele metod integrowania uwierzytelniania i autoryzacji w Xamarin.Forms aplikacji komunikującej się z aplikacją internetową MVC ASP.NET, w tym przy użyciu ASP.NET Core Identity, zewnętrznych dostawców uwierzytelniania, takich jak Microsoft, Google, Facebook lub Twitter, oraz oprogramowanie pośredniczące uwierzytelniania. Aplikacja mobilna eShopOnContainers wykonuje uwierzytelnianie i autoryzację za pomocą konteneryzowanej mikrousługi tożsamości korzystającej z serwera IdentityServer 4. Aplikacja mobilna żąda tokenów zabezpieczających z serwera IdentityServer na potrzeby uwierzytelniania użytkownika lub uzyskiwania dostępu do zasobu. Aby maszyna wirtualna IdentityServer wystawiała tokeny w imieniu użytkownika, użytkownik musi zalogować się do serwera IdentityServer. Jednak usługa IdentityServer nie udostępnia interfejsu użytkownika ani bazy danych na potrzeby uwierzytelniania. W związku z tym w aplikacji referencyjnej eShopOnContainers ASP.NET Core Identity jest używana w tym celu.

Uwierzytelnianie

Uwierzytelnianie jest wymagane, gdy aplikacja musi znać tożsamość bieżącego użytkownika. Podstawowym mechanizmem identyfikacji użytkowników ASP.NET Core jest system członkostwa w ASP.NET Core Identity, który przechowuje informacje o użytkowniku w magazynie danych skonfigurowanym przez dewelopera. Zazwyczaj ten magazyn danych będzie magazynem EntityFramework, chociaż magazyny niestandardowe lub pakiety innych firm mogą służyć do przechowywania informacji o tożsamości w usłudze Azure Storage, Usłudze Azure Cosmos DB lub innych lokalizacjach.

W przypadku scenariuszy uwierzytelniania, które korzystają z magazynu danych użytkownika lokalnego i które utrwalają informacje o tożsamości między żądaniami za pośrednictwem plików cookie (co jest typowe w aplikacjach internetowych ASP.NET MVC), ASP.NET Core Identity jest odpowiednim rozwiązaniem. Jednak pliki cookie nie zawsze są naturalnym sposobem utrwalania i przesyłania danych. Na przykład aplikacja internetowa ASP.NET Core, która uwidacznia punkty końcowe RESTful, do których uzyskuje się dostęp z aplikacji mobilnej, zwykle musi używać uwierzytelniania tokenu elementu nośnego, ponieważ pliki cookie nie mogą być używane w tym scenariuszu. Tokeny elementu nośnego można jednak łatwo pobrać i dołączyć do nagłówka autoryzacji żądań internetowych wysyłanych z aplikacji mobilnej.

Wystawianie tokenów elementu nośnego przy użyciu serwera IdentityServer 4

IdentityServer 4 to platforma open source OpenID Połączenie i OAuth 2.0 dla platformy ASP.NET Core, która może być używana w wielu scenariuszach uwierzytelniania i autoryzacji, w tym wystawiania tokenów zabezpieczających dla lokalnych użytkowników ASP.NET Core Identity.

Uwaga

Interfejsy OpenID Połączenie i OAuth 2.0 są bardzo podobne, ale mają różne obowiązki.

OpenID Połączenie to warstwa uwierzytelniania oparta na protokole OAuth 2.0. OAuth 2 to protokół, który umożliwia aplikacjom żądanie tokenów dostępu z usługi tokenu zabezpieczającego i używanie ich do komunikowania się z interfejsami API. Delegowanie zmniejsza złożoność zarówno aplikacji klienckich, jak i interfejsów API, ponieważ uwierzytelnianie i autoryzacja mogą być scentralizowane.

Połączenie interfejsu OpenID Połączenie i OAuth 2.0 łączy dwa podstawowe problemy z zabezpieczeniami uwierzytelniania i dostępu do interfejsu API, a IdentityServer 4 jest implementacją tych protokołów.

W aplikacjach korzystających z bezpośredniej komunikacji typu klient-mikrousług, takiej jak aplikacja referencyjna eShopOnContainers, dedykowana mikrousługa uwierzytelniania działająca jako usługa tokenu zabezpieczającego (STS) może służyć do uwierzytelniania użytkowników, jak pokazano na rysunku 9-1. Aby uzyskać więcej informacji na temat bezpośredniej komunikacji między klientem a mikrousługą, zobacz Komunikacja między klientem i mikrousługami.

Authentication by a dedicated authentication microservice

Rysunek 9–1. Uwierzytelnianie za pomocą dedykowanej mikrousługi uwierzytelniania

Aplikacja mobilna eShopOnContainers komunikuje się z mikrousługą tożsamości, która używa serwera IdentityServer 4 do przeprowadzania uwierzytelniania i kontroli dostępu dla interfejsów API. W związku z tym aplikacja mobilna żąda tokenów z serwera IdentityServer na potrzeby uwierzytelniania użytkownika lub uzyskiwania dostępu do zasobu:

  • Uwierzytelnianie użytkowników za pomocą usługi IdentityServer jest osiągane przez aplikację mobilną żądającą tokenu tożsamości , który reprezentuje wynik procesu uwierzytelniania. Co najmniej zawiera identyfikator użytkownika oraz informacje o tym, jak i kiedy użytkownik się uwierzytelnił. Może również zawierać dodatkowe dane tożsamości.
  • Uzyskiwanie dostępu do zasobu za pomocą usługi IdentityServer jest osiągane przez aplikację mobilną żądającą tokenu dostępu , który umożliwia dostęp do zasobu interfejsu API. Klienci żądają tokenów dostępu i przekazują je do interfejsu API. Tokeny dostępu zawierają informacje o kliencie i użytkowniku (jeśli istnieje). Następnie interfejsy API używają tych informacji do autoryzowania dostępu do danych.

Uwaga

Aby można było żądać tokenów, klient musi być zarejestrowany w usłudze IdentityServer.

Dodawanie serwera IdentityServer do aplikacji internetowej

Aby aplikacja internetowa ASP.NET Core korzystała z serwera IdentityServer 4, należy ją dodać do rozwiązania programu Visual Studio aplikacji internetowej. Aby uzyskać więcej informacji, zobacz Omówienie w dokumentacji IdentityServer.

Po dołączeniu serwera IdentityServer do rozwiązania programu Visual Studio aplikacji internetowej należy ją dodać do potoku przetwarzania żądań HTTP aplikacji internetowej, aby umożliwić obsługę żądań do punktów końcowych OpenID Połączenie i OAuth 2.0. Jest to osiągane w metodzie Configure w klasie aplikacji Startup internetowej, jak pokazano w poniższym przykładzie kodu:

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

Kolejność ma znaczenie w potoku przetwarzania żądań HTTP aplikacji internetowej. W związku z tym należy dodać serwer IdentityServer do potoku przed strukturą interfejsu użytkownika, która implementuje ekran logowania.

Konfigurowanie maszyny wirtualnej IdentityServer

Klasę ConfigureServices IdentityServer należy skonfigurować w metodzie w klasie aplikacji Startup internetowej przez wywołanie services.AddIdentityServer metody, jak pokazano w poniższym przykładzie kodu z aplikacji referencyjnej eShopOnContainers:

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>();  
}

Po wywołaniu services.AddIdentityServer metody wywoływane są dodatkowe płynne interfejsy API w celu skonfigurowania następujących elementów:

  • Poświadczenia używane do podpisywania.
  • Zasoby interfejsu API i tożsamości, do których użytkownicy mogą żądać dostępu.
  • Klienci, którzy będą łączyć się z tokenami żądań.
  • ASP.NET tożsamość podstawowa.

Napiwek

Dynamiczne ładowanie konfiguracji IdentityServer 4. Interfejsy API serwera IdentityServer 4 umożliwiają konfigurowanie serwera IdentityServer z listy obiektów konfiguracji w pamięci. W aplikacji referencyjnej eShopOnContainers te kolekcje w pamięci są zakodowane w aplikacji. Jednak w scenariuszach produkcyjnych mogą być ładowane dynamicznie z pliku konfiguracji lub z bazy danych.

Aby uzyskać informacje na temat konfigurowania maszyny wirtualnej IdentityServer do używania ASP.NET Core Identity, zobacz Using ASP.NET Core Identity (Używanie tożsamości podstawowej ASP.NET) w dokumentacji IdentityServer.

Konfigurowanie zasobów interfejsu API

Podczas konfigurowania zasobów AddInMemoryApiResources interfejsu API metoda oczekuje IEnumerable<ApiResource> kolekcji. Poniższy przykład kodu przedstawia metodę GetApis , która udostępnia tę kolekcję w aplikacji referencyjnej eShopOnContainers:

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

Ta metoda określa, że usługa IdentityServer powinna chronić interfejsy API zamówień i koszyka. W związku z tym tokeny dostępu zarządzanego identityServer będą wymagane podczas wykonywania wywołań do tych interfejsów API. Aby uzyskać więcej informacji na temat typu, zobacz Zasób interfejsu ApiResource API w dokumentacji IdentityServer 4.

Konfigurowanie zasobów tożsamości

Podczas konfigurowania zasobów AddInMemoryIdentityResources tożsamości metoda oczekuje IEnumerable<IdentityResource> kolekcji. Zasoby tożsamości to dane, takie jak identyfikator użytkownika, nazwa lub adres e-mail. Każdy zasób tożsamości ma unikatową nazwę i do niego można przypisać dowolne typy oświadczeń, które następnie zostaną uwzględnione w tokenie tożsamości użytkownika. Poniższy przykład kodu przedstawia metodę GetResources , która udostępnia tę kolekcję w aplikacji referencyjnej eShopOnContainers:

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

Specyfikacja Połączenie OpenID określa niektóre standardowe zasoby tożsamości. Minimalnym wymaganiem jest zapewnienie obsługi emitowania unikatowego identyfikatora dla użytkowników. Jest to osiągane przez uwidacznianie IdentityResources.OpenId zasobu tożsamości.

Uwaga

Klasa IdentityResources obsługuje wszystkie zakresy zdefiniowane w specyfikacji openID Połączenie (openid, email, profil, telefon i adres).

Usługa IdentityServer obsługuje również definiowanie niestandardowych zasobów tożsamości. Aby uzyskać więcej informacji na temat IdentityResource typu, zobacz Identity Resource (Zasób tożsamości) w dokumentacji IdentityServer 4.

Konfigurowanie klientów

Klienci to aplikacje, które mogą żądać tokenów z maszyny wirtualnej IdentityServer. Zazwyczaj dla każdego klienta należy zdefiniować następujące ustawienia co najmniej:

  • Unikatowy identyfikator klienta.
  • Dozwolone interakcje z usługą tokenu (nazywane typem przyznawania).
  • Lokalizacja, w której są wysyłane tożsamości i tokeny dostępu (nazywane identyfikatorem URI przekierowania).
  • Lista zasobów, do których klient ma dostęp (znany jako zakresy).

Podczas konfigurowania klientów AddInMemoryClients metoda oczekuje IEnumerable<Client> kolekcji. Poniższy przykład kodu przedstawia konfigurację aplikacji mobilnej eShopOnContainers w GetClients metodzie, która udostępnia tę kolekcję w aplikacji referencyjnej eShopOnContainers:

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
        },
        ...
    };
}

Ta konfiguracja określa dane dla następujących właściwości:

  • ClientId: unikatowy identyfikator klienta.
  • ClientName: nazwa wyświetlana klienta, która jest używana do rejestrowania i ekranu zgody.
  • AllowedGrantTypes: określa, w jaki sposób klient chce wchodzić w interakcję z maszyną wirtualną IdentityServer. Aby uzyskać więcej informacji, zobacz Konfigurowanie przepływu uwierzytelniania.
  • ClientSecrets: określa poświadczenia wpisu tajnego klienta, które są używane podczas żądania tokenów z punktu końcowego tokenu.
  • RedirectUris: określa dozwolone identyfikatory URI, do których mają być zwracane tokeny lub kody autoryzacji.
  • RequireConsent: określa, czy jest wymagany ekran zgody.
  • RequirePkce: określa, czy klienci korzystający z kodu autoryzacji muszą wysłać klucz dowodowy.
  • PostLogoutRedirectUris: określa dozwolone identyfikatory URI do przekierowania do po wylogowaniu.
  • AllowedCorsOrigins: określa źródło klienta, aby serwer IdentityServer mógł zezwalać na wywołania między źródłami z źródła.
  • AllowedScopes: określa zasoby, do których klient ma dostęp. Domyślnie klient nie ma dostępu do żadnych zasobów.
  • AllowOfflineAccess: określa, czy klient może żądać tokenów odświeżania.

Konfigurowanie przepływu uwierzytelniania

Przepływ uwierzytelniania między klientem a serwerem IdentityServer można skonfigurować, określając typy dotacji we Client.AllowedGrantTypes właściwości . Specyfikacje openID Połączenie i OAuth 2.0 definiują szereg przepływów uwierzytelniania, w tym:

  • Niejawne. Ten przepływ jest zoptymalizowany pod kątem aplikacji opartych na przeglądarce i powinien być używany tylko do uwierzytelniania użytkowników lub żądań tokenów uwierzytelniania i dostępu. Wszystkie tokeny są przesyłane za pośrednictwem przeglądarki, dlatego zaawansowane funkcje, takie jak tokeny odświeżania, nie są dozwolone.
  • Kod autoryzacji. Ten przepływ umożliwia pobieranie tokenów w kanale zaplecza, a nie kanału frontonu przeglądarki, a także obsługę uwierzytelniania klienta.
  • Hybrydowy. Ten przepływ jest kombinacją typów przyznawania kodu niejawnego i autoryzacji. Token tożsamości jest przesyłany za pośrednictwem kanału przeglądarki i zawiera podpisaną odpowiedź protokołu wraz z innymi artefaktami, takimi jak kod autoryzacji. Po pomyślnej weryfikacji odpowiedzi kanał zaplecza powinien służyć do pobierania tokenu dostępu i odświeżania.

Napiwek

Użyj przepływu uwierzytelniania hybrydowego. Przepływ uwierzytelniania hybrydowego ogranicza liczbę ataków mających zastosowanie do kanału przeglądarki i jest zalecanym przepływem dla aplikacji natywnych, które chcą pobierać tokeny dostępu (i ewentualnie odświeżać tokeny).

Aby uzyskać więcej informacji na temat przepływów uwierzytelniania, zobacz Grant Types (Udzielanie typów ) w dokumentacji identityServer 4.

Wykonywanie uwierzytelniania

Aby maszyna wirtualna IdentityServer wystawiała tokeny w imieniu użytkownika, użytkownik musi zalogować się do serwera IdentityServer. Jednak usługa IdentityServer nie udostępnia interfejsu użytkownika ani bazy danych na potrzeby uwierzytelniania. W związku z tym w aplikacji referencyjnej eShopOnContainers ASP.NET Core Identity jest używana w tym celu.

Aplikacja mobilna eShopOnContainers uwierzytelnia się za pomocą klasy IdentityServer przy użyciu przepływu uwierzytelniania hybrydowego, który przedstawiono na rysunku 9-2.

High-level overview of the sign-in process

Rysunek 9–2. Ogólne omówienie procesu logowania

Żądanie logowania jest wykonywane na adres <base endpoint>:5105/connect/authorize. Po pomyślnym uwierzytelnieniu usługa IdentityServer zwraca odpowiedź uwierzytelniania zawierającą kod autoryzacji i token tożsamości. Kod autoryzacji jest następnie wysyłany do <base endpoint>:5105/connect/tokenprogramu , który odpowiada za pomocą tokenów dostępu, tożsamości i odświeżania.

Aplikacja mobilna eShopOnContainers wylogowała się z serwera IdentityServer, wysyłając żądanie do <base endpoint>:5105/connect/endsessionobiektu z dodatkowymi parametrami. Po wylogowaniu usługa IdentityServer odpowiada, wysyłając identyfikator URI przekierowania po wylogowaniu z powrotem do aplikacji mobilnej. Rysunek 9–3 ilustruje ten proces.

High-level overview of the sign-out process

Rysunek 9–3. Ogólne omówienie procesu wylogowywanie

W aplikacji mobilnej eShopOnContainers komunikacja z maszyną wirtualną IdentityServer jest wykonywana przez klasę IdentityService , która implementuje IIdentityService interfejs. Ten interfejs określa, że klasa implementowania musi dostarczać CreateAuthorizationRequestmetody , CreateLogoutRequesti GetTokenAsync .

Logowanie

Gdy użytkownik naciągnie przycisk LOGIN w LoginViewklasie , SignInCommand zostanie wykonany element w LoginViewModel klasie, który z kolei wykonuje metodę SignInAsync . Poniższy przykład kodu przedstawia tę metodę:

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

Ta metoda wywołuje metodę CreateAuthorizationRequest w IdentityService klasie, która jest pokazana w poniższym przykładzie kodu:

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;
}

Ta metoda tworzy identyfikator URI dla punktu końcowego autoryzacji serwera IdentityServer z wymaganymi parametrami. Punkt końcowy autoryzacji znajduje się na /connect/authorize porcie 5105 podstawowego punktu końcowego uwidocznionego jako ustawienie użytkownika. Aby uzyskać więcej informacji na temat ustawień użytkownika, zobacz Zarządzanie konfiguracją.

Uwaga

Powierzchnia ataków aplikacji mobilnej eShopOnContainers jest ograniczona przez zaimplementowanie rozszerzenia Proof Key for Code Exchange (PKCE) do protokołu OAuth. PKCE chroni kod autoryzacji przed użyciem, jeśli zostanie przechwycony. Jest to osiągane przez klienta generującego weryfikator wpisów tajnych, skrót, który jest przekazywany w żądaniu autoryzacji i który jest prezentowany bez skrótu podczas realizacji kodu autoryzacji. Aby uzyskać więcej informacji na temat PKCE, zobacz Proof Key for Code Exchange by OAuth Public Clients (Klucz weryfikacji wymiany kodu przez klientów publicznych OAuth) w witrynie internetowej Grupy zadaniowej w Internecie.

Zwrócony identyfikator URI jest przechowywany we LoginUrl właściwości LoginViewModel klasy. Gdy IsLogin właściwość stanie się truewartością , WebView właściwość w LoginView obiekcie stanie się widoczna. Dane WebView wiążą jego Source właściwość z właściwością LoginUrlLoginViewModel klasy, dlatego wysyła żądanie logowania do klasy IdentityServer, gdy LoginUrl właściwość jest ustawiona na punkt końcowy autoryzacji IdentityServer. Gdy usługa IdentityServer odbierze to żądanie i użytkownik nie zostanie uwierzytelniony, WebView nastąpi przekierowanie do skonfigurowanej strony logowania, która jest wyświetlana na rysunku 9–4.

Login page displayed by the WebView

Rysunek 9–4. Strona logowania wyświetlana przez element WebView

Po zakończeniu WebView logowania nastąpi przekierowanie do zwracanego identyfikatora URI. Ta WebView nawigacja spowoduje NavigateAsync wykonanie metody w LoginViewModel klasie, która jest wyświetlana w poniższym przykładzie kodu:

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();  
        }  
    }  
    ...  
}

Ta metoda analizuje odpowiedź uwierzytelniania zawartą w zwracanym identyfikatorze URI i pod warunkiem, że istnieje prawidłowy kod autoryzacji, wysyła żądanie do punktu końcowego tokenu IdentityServer, przekazując kod autoryzacji, weryfikator wpisów tajnych PKCE i inne wymagane parametry. Punkt końcowy tokenu znajduje się na /connect/token porcie 5105 podstawowego punktu końcowego uwidocznionego jako ustawienie użytkownika. Aby uzyskać więcej informacji na temat ustawień użytkownika, zobacz Zarządzanie konfiguracją.

Napiwek

Zweryfikuj zwracane identyfikatory URI. Mimo że aplikacja mobilna eShopOnContainers nie weryfikuje zwracanego identyfikatora URI, najlepszym rozwiązaniem jest sprawdzenie, czy zwracany identyfikator URI odwołuje się do znanej lokalizacji, aby zapobiec atakom typu open-redirect.

Jeśli punkt końcowy tokenu otrzyma prawidłowy kod autoryzacji i weryfikator wpisów tajnych PKCE, odpowiada za pomocą tokenu dostępu, tokenu tożsamości i tokenu odświeżania. Token dostępu (który umożliwia dostęp do zasobów interfejsu API) i token tożsamości są następnie przechowywane jako ustawienia aplikacji, a nawigacja po stronie jest wykonywana. W związku z tym ogólny efekt w aplikacji mobilnej eShopOnContainers jest następujący: pod warunkiem, że użytkownicy będą mogli pomyślnie uwierzytelnić się za pomocą identityServer, są one nawigowane do MainView strony, która jest TabbedPage wyświetlana CatalogView jako wybrana karta.

Aby uzyskać informacje na temat nawigacji między stronami, zobacz Nawigacja. Aby uzyskać informacje na temat sposobu, w jaki WebView nawigacja powoduje wykonanie metody modelu widoku, zobacz Wywoływanie nawigacji przy użyciu zachowań. Aby uzyskać informacje o ustawieniach aplikacji, zobacz Zarządzanie konfiguracją.

Uwaga

Aplikacja eShopOnContainers umożliwia również pozorne logowanie, gdy aplikacja jest skonfigurowana do korzystania z pozornych usług w programie SettingsView. W tym trybie aplikacja nie komunikuje się z usługą IdentityServer, zamiast tego zezwala użytkownikowi na logowanie się przy użyciu poświadczeń.

Wylogowywanie

Gdy użytkownik naciągnie przycisk Wyloguj się w ProfileViewklasie , LogoutCommand zostanie wykonany element w ProfileViewModel klasie, który z kolei wykonuje metodę LogoutAsync . Ta metoda wykonuje nawigację po LoginView stronie, przekazując LogoutParameter wystąpienie ustawione jako true parametr. Aby uzyskać więcej informacji na temat przekazywania parametrów podczas nawigacji na stronie, zobacz Przekazywanie parametrów podczas nawigacji.

Po utworzeniu widoku i przejściu do InitializeAsync niej jest wykonywana metoda skojarzonego modelu widoku, która następnie wykonuje Logout metodę LoginViewModel klasy, która jest wyświetlana w poniższym przykładzie kodu:

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

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

Ta metoda wywołuje metodę CreateLogoutRequest w IdentityService klasie, przekazując token tożsamości pobrany z ustawień aplikacji jako parametr. Aby uzyskać więcej informacji na temat ustawień aplikacji, zobacz Zarządzanie konfiguracją. Poniższy przykład kodu przedstawia metodę CreateLogoutRequest :

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);  
}

Ta metoda tworzy identyfikator URI do końcowego punktu końcowego sesji serwera IdentityServer z wymaganymi parametrami. Punkt końcowy sesji znajduje się na /connect/endsession porcie 5105 podstawowego punktu końcowego uwidocznionego jako ustawienie użytkownika. Aby uzyskać więcej informacji na temat ustawień użytkownika, zobacz Zarządzanie konfiguracją.

Zwrócony identyfikator URI jest przechowywany we LoginUrl właściwości LoginViewModel klasy. IsLogin Gdy właściwość ma truewartość , WebView właściwość w obiekcie jest widocznaLoginView. Dane WebView wiążą jego Source właściwość z LoginUrl właściwością LoginViewModel klasy, dlatego wysyła żądanie wylogowania do klasy IdentityServer, gdy LoginUrl właściwość jest ustawiona na punkt końcowy sesji identityServer. Gdy usługa IdentityServer odbierze to żądanie, pod warunkiem, że użytkownik jest zalogowany, wyloguj się. Uwierzytelnianie jest śledzone za pomocą pliku cookie zarządzanego przez oprogramowanie pośredniczące uwierzytelniania plików cookie z ASP.NET Core. W związku z tym wylogowanie się z serwera IdentityServer usuwa plik cookie uwierzytelniania i wysyła identyfikator URI przekierowania po wylogowaniu z powrotem do klienta.

W aplikacji WebView mobilnej element zostanie przekierowany do identyfikatora URI przekierowania po wylogowaniu. Ta WebView nawigacja spowoduje NavigateAsync wykonanie metody w LoginViewModel klasie, która jest wyświetlana w poniższym przykładzie kodu:

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

Ta metoda czyści zarówno token tożsamości, jak i token dostępu z ustawień aplikacji, i ustawia IsLogin właściwość na falsewartość , co powoduje WebView , że na LoginView stronie stanie się niewidoczny. LoginUrl Na koniec właściwość jest ustawiona na identyfikator URI punktu końcowego autoryzacji identityServer z wymaganymi parametrami w ramach przygotowań do następnego zainicjowania logowania przez użytkownika.

Aby uzyskać informacje na temat nawigacji między stronami, zobacz Nawigacja. Aby uzyskać informacje na temat sposobu, w jaki WebView nawigacja powoduje wykonanie metody modelu widoku, zobacz Wywoływanie nawigacji przy użyciu zachowań. Aby uzyskać informacje o ustawieniach aplikacji, zobacz Zarządzanie konfiguracją.

Uwaga

EShopOnContainers umożliwia również pozorne wylogowywanie, gdy aplikacja jest skonfigurowana do korzystania z pozornych usług w Ustawienia View. W tym trybie aplikacja nie komunikuje się z usługą IdentityServer i zamiast tego czyści wszystkie przechowywane tokeny z ustawień aplikacji.

Autoryzacja

Po uwierzytelnieniu ASP.NET Core internetowych interfejsów API często muszą autoryzować dostęp, co umożliwia usłudze udostępnianie interfejsów API niektórym uwierzytelnionymi użytkownikom, ale nie wszystkim.

Ograniczenie dostępu do trasy ASP.NET Core MVC można osiągnąć, stosując atrybut Authorize do kontrolera lub akcji, co ogranicza dostęp do kontrolera lub akcji dla uwierzytelnionych użytkowników, jak pokazano w poniższym przykładzie kodu:

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

Jeśli nieautoryzowany użytkownik próbuje uzyskać dostęp do kontrolera lub akcji oznaczonej atrybutem Authorize , struktura MVC zwraca kod stanu HTTP 401 (nieautoryzowany).

Uwaga

Parametry można określić na atrybucie, Authorize aby ograniczyć interfejs API do określonych użytkowników. Aby uzyskać więcej informacji, zobacz Autoryzacja.

Serwer IdentityServer można zintegrować z przepływem pracy autoryzacji, aby tokeny dostępu zapewniały autoryzację kontroli. To podejście przedstawiono na rysunku 9–5.

Authorization by access token

Rysunek 9–5. Autoryzacja według tokenu dostępu

Aplikacja mobilna eShopOnContainers komunikuje się z mikrousługą tożsamości i żąda tokenu dostępu w ramach procesu uwierzytelniania. Token dostępu jest następnie przekazywany do interfejsów API udostępnianych przez mikrousługi zamawiania i koszyka w ramach żądań dostępu. Tokeny dostępu zawierają informacje o kliencie i użytkowniku. Następnie interfejsy API używają tych informacji do autoryzowania dostępu do danych. Aby uzyskać informacje o sposobie konfigurowania serwera IdentityServer w celu ochrony interfejsów API, zobacz Konfigurowanie zasobów interfejsu API.

Konfigurowanie maszyny wirtualnej IdentityServer do wykonania autoryzacji

Aby wykonać autoryzację za pomocą serwera IdentityServer, jego oprogramowanie pośredniczące autoryzacji musi zostać dodane do potoku żądania HTTP aplikacji internetowej. Oprogramowanie pośredniczące jest dodawane w metodzie ConfigureAuth w klasie aplikacji Startup internetowej, która jest wywoływana z Configure metody i jest pokazana w poniższym przykładzie kodu z aplikacji referencyjnej eShopOnContainers:

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

Ta metoda zapewnia dostęp do interfejsu API tylko przy użyciu prawidłowego tokenu dostępu. Oprogramowanie pośredniczące weryfikuje token przychodzący, aby upewnić się, że jest wysyłany z zaufanego wystawcy i sprawdza, czy token jest prawidłowy do użycia z interfejsem API, który go odbiera. W związku z tym przejście do kontrolera zamówienia lub koszyka zwróci kod stanu HTTP 401 (nieautoryzowany) wskazujący, że token dostępu jest wymagany.

Uwaga

Oprogramowanie pośredniczące autoryzacji serwera IdentityServer musi zostać dodane do potoku żądania HTTP aplikacji internetowej przed dodaniem wzorca MVC za pomocą app.UseMvc() polecenia lub app.UseMvcWithDefaultRoute().

Wykonywanie żądań dostępu do interfejsów API

Podczas wprowadzania żądań do mikrousług zamówień i koszyka token dostępu uzyskany z serwera IdentityServer podczas procesu uwierzytelniania musi zostać uwzględniony w żądaniu, jak pokazano w poniższym przykładzie kodu:

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

Token dostępu jest przechowywany jako ustawienie aplikacji i jest pobierany z magazynu specyficznego dla platformy i dołączony do wywołania GetOrderAsync metody w OrderService klasie .

Podobnie token dostępu musi zostać uwzględniony podczas wysyłania danych do chronionego interfejsu API IdentityServer, jak pokazano w poniższym przykładzie kodu:

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

Token dostępu jest pobierany z magazynu specyficznego dla platformy i uwzględniany w wywołaniu UpdateBasketAsync metody w BasketService klasie .

Klasa RequestProvider w aplikacji mobilnej eShopOnContainers używa HttpClient klasy do przesyłania żądań do interfejsów API RESTful uwidocznionych przez aplikację referencyjną eShopOnContainers. Podczas wprowadzania żądań do interfejsów API zamawiania i koszyka, które wymagają autoryzacji, należy dołączyć prawidłowy token dostępu do żądania. Jest to osiągane przez dodanie tokenu dostępu do nagłówków HttpClient wystąpienia, jak pokazano w poniższym przykładzie kodu:

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

Właściwość DefaultRequestHeadersHttpClient klasy uwidacznia nagłówki wysyłane za pomocą każdego żądania, a token dostępu jest dodawany do Authorization nagłówka poprzedzonego ciągiem Bearer. Gdy żądanie jest wysyłane do interfejsu API RESTful, wartość Authorization nagłówka jest wyodrębniona i weryfikowana, aby upewnić się, że jest wysyłany z zaufanego wystawcy i służy do określania, czy użytkownik ma uprawnienia do wywoływania interfejsu API, który go odbiera.

Aby uzyskać więcej informacji na temat sposobu, w jaki aplikacja mobilna eShopOnContainers wysyła żądania internetowe, zobacz Uzyskiwanie dostępu do danych zdalnych.

Podsumowanie

Istnieje wiele metod integrowania uwierzytelniania i autoryzacji w aplikacji komunikującej się z aplikacją Xamarin.Forms internetową MVC ASP.NET. Aplikacja mobilna eShopOnContainers wykonuje uwierzytelnianie i autoryzację za pomocą konteneryzowanej mikrousługi tożsamości korzystającej z serwera IdentityServer 4. IdentityServer to platforma open source OpenID Połączenie i OAuth 2.0 dla platformy ASP.NET Core, która integruje się z ASP.NET Core Identity w celu przeprowadzania uwierzytelniania tokenu elementu nośnego.

Aplikacja mobilna żąda tokenów zabezpieczających z serwera IdentityServer na potrzeby uwierzytelniania użytkownika lub uzyskiwania dostępu do zasobu. Podczas uzyskiwania dostępu do zasobu token dostępu musi być uwzględniony w żądaniu do interfejsów API, które wymagają autoryzacji. Oprogramowanie pośredniczące IdentityServer weryfikuje przychodzące tokeny dostępu, aby upewnić się, że są wysyłane z zaufanego wystawcy i że są one prawidłowe do użycia z interfejsem API, który je odbiera.