Autenticazione e autorizzazione

Nota

Questo eBook è stato pubblicato nella primavera del 2017 e non è stato aggiornato da allora. C'è molto nel libro che rimane prezioso, ma alcuni dei materiali sono obsoleti.

L'autenticazione è il processo di recupero delle credenziali di identificazione, ad esempio nome e password da un utente, e convalida di tali credenziali rispetto a un'autorità. Se le credenziali sono valide, l'entità che ha inviato le credenziali viene considerata un'identità autenticata. Dopo l'autenticazione di un'identità, un processo di autorizzazione determina se tale identità ha accesso a una determinata risorsa.

Esistono molti approcci per l'integrazione dell'autenticazione e dell'autorizzazione in un'app Xamarin.Forms che comunica con un'applicazione Web MVC ASP.NET, tra cui l'uso di ASP.NET Core Identity, provider di autenticazione esterni come Microsoft, Google, Facebook o Twitter e il middleware di autenticazione. L'app per dispositivi mobili eShopOnContainers esegue l'autenticazione e l'autorizzazione con un microservizio di identità in contenitori che usa IdentityServer 4. L'app per dispositivi mobili richiede token di sicurezza da IdentityServer, per l'autenticazione di un utente o per l'accesso a una risorsa. Affinché IdentityServer rilasci i token per conto di un utente, l'utente deve accedere a IdentityServer. IdentityServer, tuttavia, non fornisce un'interfaccia utente o un database per l'autenticazione. Pertanto, nell'applicazione di riferimento eShopOnContainers, ASP.NET Core Identity viene usato a questo scopo.

Autenticazione

L'autenticazione è necessaria quando un'applicazione deve conoscere l'identità dell'utente corrente. ASP.NET il meccanismo principale di Core per identificare gli utenti è il sistema di appartenenza ASP.NET Core Identity, che archivia le informazioni utente in un archivio dati configurato dallo sviluppatore. In genere, questo archivio dati sarà un archivio EntityFramework, anche se gli archivi personalizzati o i pacchetti di terze parti possono essere usati per archiviare le informazioni sull'identità in Archiviazione di Azure, Azure Cosmos DB o in altre posizioni.

Per gli scenari di autenticazione che usano un archivio dati utente locale e che rendono persistenti le informazioni sull'identità tra le richieste tramite cookie (come in genere nelle applicazioni Web MVC ASP.NET), ASP.NET Core Identity è una soluzione adatta. Tuttavia, i cookie non sono sempre un mezzo naturale per rendere persistenti e trasmettere i dati. Ad esempio, un'applicazione Web ASP.NET Core che espone gli endpoint RESTful a cui si accede da un'app per dispositivi mobili in genere dovrà usare l'autenticazione del token di connessione, poiché i cookie non possono essere usati in questo scenario. Tuttavia, i token di connessione possono essere facilmente recuperati e inclusi nell'intestazione di autorizzazione delle richieste Web effettuate dall'app per dispositivi mobili.

Emissione di token di connessione con IdentityServer 4

IdentityServer 4 è un framework OpenID open source Connessione e OAuth 2.0 per ASP.NET Core, che può essere usato per molti scenari di autenticazione e autorizzazione, tra cui l'emissione di token di sicurezza per gli utenti locali ASP.NET Core Identity.

Nota

OpenID Connect e OAuth 2.0 sono molto simili, pur avendo responsabilità diverse.

OpenID Connect è un livello di autenticazione sopra il protocollo OAuth 2.0. OAuth 2 è un protocollo che consente alle applicazioni di richiedere token di accesso da un servizio token di sicurezza e usarli per comunicare con le API. Questa delega riduce la complessità sia nelle applicazioni client che nelle API, perché l'autenticazione e l'autorizzazione possono essere centralizzate.

La combinazione di OpenID Connessione e OAuth 2.0 combina i due principali problemi di sicurezza relativi all'autenticazione e all'accesso api e IdentityServer 4 è un'implementazione di questi protocolli.

Nelle applicazioni che usano la comunicazione diretta da client a microservizi, ad esempio l'applicazione di riferimento eShopOnContainers, un microservizio di autenticazione dedicato che funge da servizio token di sicurezza (STS) può essere usato per autenticare gli utenti, come illustrato nella figura 9-1. Per altre informazioni sulla comunicazione diretta da client a microservizio, vedere Comunicazione tra client e microservizi.

Authentication by a dedicated authentication microservice

Figura 9-1: Autenticazione tramite un microservizio di autenticazione dedicato

L'app per dispositivi mobili eShopOnContainers comunica con il microservizio identity, che usa IdentityServer 4 per eseguire l'autenticazione e il controllo di accesso per le API. Di conseguenza, l'app per dispositivi mobili richiede token da IdentityServer, per l'autenticazione di un utente o per l'accesso a una risorsa:

  • L'autenticazione degli utenti con IdentityServer viene ottenuta dall'app per dispositivi mobili che richiede un token di identità , che rappresenta il risultato di un processo di autenticazione. Al minimo, contiene un identificatore per l'utente e informazioni su come e quando l'utente ha eseguito l'autenticazione. Può anche contenere dati di identità aggiuntivi.
  • L'accesso a una risorsa con IdentityServer viene ottenuto dall'app per dispositivi mobili che richiede un token di accesso , che consente l'accesso a una risorsa API. I client richiedono token di accesso e li inoltrano all'API. I token di accesso contengono informazioni sul client e sull'utente (se presente). Le API usano quindi tali informazioni per autorizzare l'accesso ai dati.

Nota

Prima di poter richiedere token, è necessario registrare un client con IdentityServer.

Aggiunta di IdentityServer a un'applicazione Web

Affinché un'applicazione Web ASP.NET Core usi IdentityServer 4, è necessario aggiungerla alla soluzione Visual Studio dell'applicazione Web. Per altre informazioni, vedere Panoramica nella documentazione di IdentityServer.

Dopo aver incluso IdentityServer nella soluzione Visual Studio dell'applicazione Web, deve essere aggiunto alla pipeline di elaborazione delle richieste HTTP dell'applicazione Web, in modo che possa gestire le richieste agli endpoint OpenID Connessione e OAuth 2.0. Questo risultato viene ottenuto nel metodo Configure nella classe Startup dell'applicazione Web, come illustrato nell'esempio di codice seguente:

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

L'ordine è importante nella pipeline di elaborazione delle richieste HTTP dell'applicazione Web. Pertanto, IdentityServer deve essere aggiunto alla pipeline prima del framework dell'interfaccia utente che implementa la schermata di accesso.

Configurazione di IdentityServer

IdentityServer deve essere configurato nel ConfigureServices metodo nella classe dell'applicazione Startup Web chiamando il services.AddIdentityServer metodo , come illustrato nell'esempio di codice seguente dall'applicazione di riferimento 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>();  
}

Dopo aver chiamato il metodo services.AddIdentityServer, vengono chiamate API Fluent aggiuntive per configurare quanto segue:

  • Credenziali usate per la firma.
  • Risorse API e identità a cui gli utenti potrebbero richiedere l'accesso.
  • Client che si connetteranno ai token di richiesta.
  • Identità di ASP.NET Core.

Suggerimento

Caricare dinamicamente la configurazione di IdentityServer 4. Le API di IdentityServer 4 consentono di configurare IdentityServer da un elenco in memoria di oggetti di configurazione. Nell'applicazione di riferimento eShopOnContainers, queste raccolte in memoria sono hardcoded nell'applicazione. Tuttavia, negli scenari di produzione possono essere caricati dinamicamente da un file di configurazione o da un database.

Per informazioni sulla configurazione di IdentityServer per l'uso di Identità di ASP.NET Core, vedere Uso di Identità di ASP.NET Core nella documentazione di IdentityServer.

Configurazione delle risorse DELL'API

Quando si configurano le risorse API, il metodo AddInMemoryApiResources prevede una raccolta IEnumerable<ApiResource>. L'esempio di codice seguente illustra il metodo GetApis che fornisce questa raccolta nell'applicazione di riferimento eShopOnContainers:

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

Questo metodo specifica che IdentityServer deve proteggere gli ordini e le API carrello. Pertanto, i token di accesso gestito identityServer saranno necessari quando si effettuano chiamate a queste API. Per altre informazioni sul tipo di ApiResource, vedere risorsa API nella documentazione di IdentityServer 4.

Configurazione delle risorse di identità

Quando si configurano le risorse di identità, il metodo AddInMemoryIdentityResources prevede una raccolta IEnumerable<IdentityResource>. Le risorse di identità sono dati come ID utente, nome o indirizzo di posta elettronica. A ogni risorsa di identità è associato un nome univoco e possono essere assegnati tipi di attestazione arbitrari, che verranno quindi inclusi nel token di identità per l'utente. L'esempio di codice seguente illustra il metodo GetResources che fornisce questa raccolta nell'applicazione di riferimento eShopOnContainers:

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

La specifica OpenID Connect specifica alcune risorse di identità standard. Il requisito minimo è che il supporto venga fornito per l'emissione di un ID univoco per gli utenti. Questa operazione viene ottenuta esponendo la risorsa di identità IdentityResources.OpenId.

Nota

La IdentityResources classe supporta tutti gli ambiti definiti nella specifica openID Connessione (openid, posta elettronica, profilo, telefono e indirizzo).

IdentityServer supporta anche la definizione di risorse di identità personalizzate. Per altre informazioni sul IdentityResource tipo, vedere Identity Resource (Risorsa identità ) nella documentazione di IdentityServer 4.

Configurazione dei client

I client sono applicazioni che possono richiedere token da IdentityServer. In genere, le impostazioni seguenti devono essere definite per ogni client come minimo:

  • ID client univoco.
  • Interazioni consentite con il servizio token (noto come tipo di concessione).
  • Posizione in cui vengono inviati i token di identità e di accesso (noto come URI di reindirizzamento).
  • Elenco di risorse a cui è consentito l'accesso al client (noto come ambiti).

Quando si configurano i client, il metodo AddInMemoryClients prevede una raccolta IEnumerable<Client>. L'esempio di codice seguente illustra la configurazione per l'app per dispositivi mobili eShopOnContainers nel GetClients metodo che fornisce questa raccolta nell'applicazione di riferimento 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
        },
        ...
    };
}

Questa configurazione specifica i dati per le proprietà seguenti:

  • ClientId: ID univoco per il client.
  • ClientName: nome visualizzato del client, usato per la registrazione e la schermata di consenso.
  • AllowedGrantTypes: specifica il modo in cui un client vuole interagire con IdentityServer. Per altre informazioni, vedere Configurazione del flusso di autenticazione.
  • ClientSecrets: specifica le credenziali del segreto client usate durante la richiesta di token dall'endpoint del token.
  • RedirectUris: specifica gli URI consentiti a cui restituire token o codici di autorizzazione.
  • RequireConsent: specifica se è necessaria una schermata di consenso.
  • RequirePkce: specifica se i client che usano un codice di autorizzazione devono inviare una chiave di prova.
  • PostLogoutRedirectUris: specifica gli URI consentiti da reindirizzare a dopo la disconnessione.
  • AllowedCorsOrigins: specifica l'origine del client in modo che IdentityServer possa consentire chiamate tra le origini dall'origine.
  • AllowedScopes: specifica le risorse a cui il client ha accesso. Per impostazione predefinita, un client non ha accesso ad alcuna risorsa.
  • AllowOfflineAccess: specifica se il client può richiedere token di aggiornamento.

Configurazione del flusso di autenticazione

Il flusso di autenticazione tra un client e IdentityServer può essere configurato specificando i tipi di concessione nella proprietà Client.AllowedGrantTypes. Le specifiche OpenID Connessione e OAuth 2.0 definiscono diversi flussi di autenticazione, tra cui:

  • Implicita. Questo flusso è ottimizzato per le applicazioni basate su browser e deve essere usato solo per l'autenticazione dell’utente, o per le richieste di autenticazione e token di accesso. Tutti i token vengono trasmessi tramite il browser e pertanto non sono consentite funzionalità avanzate come i token di aggiornamento.
  • Codice di autorizzazione. Questo flusso offre la possibilità di recuperare i token in un canale back, anziché il canale anteriore del browser, supportando anche l'autenticazione client.
  • Ibrido. Questo flusso è una combinazione dei tipi di concessione del codice implicito e di autorizzazione. Il token di identità viene trasmesso tramite il canale del browser e contiene la risposta del protocollo firmata insieme ad altri artefatti, ad esempio il codice di autorizzazione. Dopo aver completato la convalida della risposta, il canale back deve essere usato per recuperare l'accesso e il token di aggiornamento.

Suggerimento

Usare il flusso di autenticazione ibrida. Il flusso di autenticazione ibrida riduce una serie di attacchi che si applicano al canale del browser ed è il flusso consigliato per le applicazioni native che vogliono recuperare i token di accesso (ed eventualmente aggiornare i token).

Per altre informazioni sui flussi di autenticazione, vedere Concedere tipi nella documentazione di IdentityServer 4.

Esecuzione dell'autenticazione

Affinché IdentityServer rilasci i token per conto di un utente, l'utente deve accedere a IdentityServer. IdentityServer, tuttavia, non fornisce un'interfaccia utente o un database per l'autenticazione. Pertanto, nell'applicazione di riferimento eShopOnContainers, ASP.NET Core Identity viene usato a questo scopo.

L'app per dispositivi mobili eShopOnContainers esegue l'autenticazione con IdentityServer con il flusso di autenticazione ibrida, illustrato nella figura 9-2.

High-level overview of the sign-in process

Figura 9-2: Panoramica generale del processo di accesso

Viene effettuata una richiesta di accesso a <base endpoint>:5105/connect/authorize. Dopo l'autenticazione riuscita, IdentityServer restituisce una risposta di autenticazione contenente un codice di autorizzazione e un token di identità. Il codice di autorizzazione viene quindi inviato a <base endpoint>:5105/connect/token, che risponde con token di accesso, identità e aggiornamento.

L'app per dispositivi mobili eShopOnContainers si disconnette da IdentityServer inviando una richiesta a <base endpoint>:5105/connect/endsession, con parametri aggiuntivi. Dopo la disconnessione, IdentityServer risponde inviando un URI di reindirizzamento di reindirizzamento post disconnessione all'app per dispositivi mobili. La figura 9-3 illustra questo processo.

High-level overview of the sign-out process

Figura 9-3: Panoramica generale del processo di disconnesso

Nell'app per dispositivi mobili eShopOnContainers la comunicazione con IdentityServer viene eseguita dalla IdentityService classe , che implementa l'interfaccia IIdentityService . Questa interfaccia specifica che la classe di implementazione deve fornire metodi CreateAuthorizationRequest, CreateLogoutRequest e GetTokenAsync.

Accesso

Quando l'utente tocca il pulsante LOGIN in LoginView, viene eseguito l'oggetto SignInCommand nella LoginViewModel classe , che a sua volta esegue il SignInAsync metodo . L'esempio di codice seguente illustra il metodo:

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

Questo metodo richiama il CreateAuthorizationRequest metodo nella IdentityService classe , illustrato nell'esempio di codice seguente:

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

Questo metodo crea l'URI per l'endpoint di autorizzazione di IdentityServer, con i parametri obbligatori. L'endpoint di autorizzazione si trova a /connect/authorize sulla porta 5105 dell'endpoint di base esposto come impostazione utente. Per altre informazioni sulle impostazioni utente, vedere Gestione della configurazione.

Nota

La superficie di attacco dell'app per dispositivi mobili eShopOnContainers viene ridotta implementando l'estensione Proof Key for Code Exchange (PKCE) in OAuth. PKCE protegge il codice di autorizzazione dall'uso se viene intercettato. Questo risultato viene ottenuto dal client generando un verificatore segreto, il cui hash viene passato nella richiesta di autorizzazione e che viene presentato senza hash durante il riscatto del codice di autorizzazione. Per altre informazioni su PKCE, vedere Proof Key for Code Exchange by OAuth Public Clients (Chiave di prova per Exchange di client pubblici OAuth) nel sito Web Internet Engineering Task Force.

L'URI restituito viene archiviato nella proprietà LoginUrl della classe LoginViewModel. Quando la IsLogin proprietà diventa true, l'oggetto LoginViewWebView in diventa visibile. I WebView dati associano la SourceLoginUrl proprietà alla proprietà della LoginViewModel classe e quindi effettua una richiesta di accesso a IdentityServer quando la LoginUrl proprietà è impostata sull'endpoint di autorizzazione di IdentityServer. Quando IdentityServer riceve questa richiesta e l'utente non è autenticato, WebView verrà reindirizzato alla pagina di accesso configurata, illustrata nella figura 9-4.

Login page displayed by the WebView

Figura 9-4: Pagina di accesso visualizzata da WebView

Al termine dell'accesso, WebView verrà reindirizzato a un URI restituito. Questa navigazione WebView causerà l'esecuzione del metodo NavigateAsync nella classe LoginViewModel, come illustrato nell'esempio di codice seguente:

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

Questo metodo analizza la risposta di autenticazione contenuta nell'URI restituito e, purché sia presente un codice di autorizzazione valido, effettua una richiesta all'endpoint token di IdentityServer, passando il codice di autorizzazione, il verifier del segreto PKCE e altri parametri obbligatori. L'endpoint del token si trova a /connect/token sulla porta 5105 dell'endpoint di base esposto come impostazione utente. Per altre informazioni sulle impostazioni utente, vedere Gestione della configurazione.

Suggerimento

Convalidare gli URI restituiti. Anche se l'app per dispositivi mobili eShopOnContainers non convalida l'URI restituito, la procedura consigliata consiste nel verificare che l'URI restituito faccia riferimento a una posizione nota, per evitare attacchi di reindirizzamento aperto.

Se l'endpoint del token riceve un codice di autorizzazione valido e un classificatore segreto PKCE, risponde con un token di accesso, un token di identità e un token di aggiornamento. Il token di accesso (che consente l'accesso alle risorse API) e il token di identità vengono quindi archiviati come impostazioni dell'applicazione e viene eseguita la navigazione nella pagina. Pertanto, l'effetto complessivo nell'app per dispositivi mobili eShopOnContainers è questo: a condizione che gli utenti siano in grado di eseguire correttamente l'autenticazione con IdentityServer, vengono spostati alla MainView pagina, ovvero un TabbedPage oggetto che visualizza CatalogView come scheda selezionata.

Per informazioni sullo spostamento tra le pagine, vedere Navigazione. Per informazioni sulla modalità WebView di esecuzione di un metodo del modello di visualizzazione, vedere Richiamo dello spostamento tramite comportamenti. Per informazioni sulle impostazioni dell'applicazione, vedere Gestione della configurazione.

Nota

EShopOnContainers consente anche un accesso fittizio quando l'app è configurata per l'uso di servizi fittizi in SettingsView. In questa modalità, l'app non comunica con IdentityServer, consentendo invece all'utente di accedere usando le credenziali.

Disconnessione

Quando l'utente tocca il pulsante LOG OUT in ProfileView, viene eseguito l'oggetto LogoutCommand nella ProfileViewModel classe , che a sua volta esegue il LogoutAsync metodo . Questo metodo esegue lo spostamento di pagina alla pagina LoginView, passando un'istanza LogoutParameter impostata su true come parametro. Per altre informazioni sul passaggio di parametri durante la navigazione nella pagina, vedere Passaggio di parametri durante la navigazione.

Quando viene creata e navigata una vista, viene eseguito il metodo InitializeAsync del modello di visualizzazione associato alla visualizzazione, che esegue quindi il metodo Logout della classe LoginViewModel, illustrato nell'esempio di codice seguente:

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

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

Questo metodo richiama il metodo CreateLogoutRequest nella classe IdentityService, passando il token di identità recuperato dalle impostazioni dell'applicazione come parametro. Per altre informazioni sulle impostazioni dell'applicazione, vedere Gestione della configurazione. L'esempio di codice seguente illustra il metodo 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);  
}

Questo metodo crea l'URI per l'endpoint di sessione finale di IdentityServer, con i parametri necessari. L'endpoint della sessione finale si trova a /connect/endsession sulla porta 5105 dell'endpoint di base esposto come impostazione utente. Per altre informazioni sulle impostazioni utente, vedere Gestione della configurazione.

L'URI restituito viene archiviato nella proprietà LoginUrl della classe LoginViewModel. Mentre la IsLogin proprietà è true, l'oggetto LoginViewWebView in è visibile. I WebView dati associano la SourceLoginUrl proprietà alla proprietà della LoginViewModel classe e quindi effettua una richiesta di disconnessione a IdentityServer quando la LoginUrl proprietà è impostata sull'endpoint della sessione finale di IdentityServer. Quando IdentityServer riceve questa richiesta, purché l'utente sia connesso, si verifica la disconnessione. L'autenticazione viene rilevata con un cookie gestito dal middleware di autenticazione dei cookie da ASP.NET Core. Di conseguenza, la disconnessione da IdentityServer rimuove il cookie di autenticazione e invia un URI di reindirizzamento post disconnessione al client.

Nell'app per dispositivi mobili, WebView verrà reindirizzato all'URI di reindirizzamento post disconnessione. Questa navigazione WebView causerà l'esecuzione del metodo NavigateAsync nella classe LoginViewModel, come illustrato nell'esempio di codice seguente:

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

Questo metodo cancella sia il token di identità che il token di accesso dalle impostazioni dell'applicazione e imposta la IsLogin proprietà su false, che fa sì che nella WebViewLoginView pagina diventi invisibile. Infine, la proprietà LoginUrl viene impostata sull'URI dell'endpoint di autorizzazione identityServer, con i parametri obbligatori, in preparazione alla successiva esecuzione dell'accesso da parte dell'utente.

Per informazioni sullo spostamento tra le pagine, vedere Navigazione. Per informazioni sulla modalità WebView di esecuzione di un metodo del modello di visualizzazione, vedere Richiamo dello spostamento tramite comportamenti. Per informazioni sulle impostazioni dell'applicazione, vedere Gestione della configurazione.

Nota

EShopOnContainers consente anche una disconnessione fittizia quando l'app è configurata per l'uso di servizi fittizi nel Impostazioni View. In questa modalità, l'app non comunica con IdentityServer e cancella invece i token archiviati dalle impostazioni dell'applicazione.

Autorizzazione

Dopo l'autenticazione, ASP.NET API Web core spesso devono autorizzare l'accesso, che consente a un servizio di rendere disponibili api ad alcuni utenti autenticati, ma non a tutti.

È possibile limitare l'accesso a una route MVC core ASP.NET applicando un attributo Authorize a un controller o a un'azione, che limita l'accesso al controller o all'azione agli utenti autenticati, come illustrato nell'esempio di codice seguente:

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

Se un utente non autorizzato tenta di accedere a un controller o a un'azione contrassegnata con l'attributo Authorize , il framework MVC restituisce un codice di stato HTTP 401 (non autorizzato).

Nota

I parametri possono essere specificati nell'attributo per limitare un'API Authorize a utenti specifici. Per altre informazioni, vedere Autorizzazione.

IdentityServer può essere integrato nel flusso di lavoro di autorizzazione in modo che i token di accesso forniscano l'autorizzazione di controllo. Questo approccio è illustrato nella figura 9-5.

Authorization by access token

Figura 9-5: Autorizzazione per token di accesso

L'app per dispositivi mobili eShopOnContainers comunica con il microservizio identity e richiede un token di accesso come parte del processo di autenticazione. Il token di accesso viene quindi inoltrato alle API esposte dai microservizi di ordinamento e carrello come parte delle richieste di accesso. I token di accesso contengono informazioni sul client e sull'utente. Le API usano quindi tali informazioni per autorizzare l'accesso ai dati. Per informazioni su come configurare IdentityServer per proteggere le API, vedere Configurazione delle risorse API.

Configurazione di IdentityServer per l'esecuzione dell'autorizzazione

Per eseguire l'autorizzazione con IdentityServer, è necessario aggiungere il middleware di autorizzazione alla pipeline di richiesta HTTP dell'applicazione Web. Il middleware viene aggiunto nel ConfigureAuth metodo nella classe dell'applicazione Startup Web, che viene richiamata dal Configure metodo ed è illustrato nell'esempio di codice seguente dell'applicazione di riferimento eShopOnContainers:

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

Questo metodo garantisce che l'API sia accessibile solo con un token di accesso valido. Il middleware convalida il token in ingresso per assicurarsi che venga inviato da un'autorità di certificazione attendibile e convalida che il token sia valido per essere usato con l'API che lo riceve. Pertanto, l'esplorazione del controller di ordinamento o carrello restituirà un codice di stato HTTP 401 (non autorizzato), a indicare che è necessario un token di accesso.

Nota

Il middleware di autorizzazione di IdentityServer deve essere aggiunto alla pipeline di richiesta HTTP dell'applicazione Web prima di aggiungere MVC con app.UseMvc() o app.UseMvcWithDefaultRoute().

Effettuare richieste di accesso alle API

Quando si effettuano richieste ai microservizi di ordinamento e carrello, il token di accesso ottenuto da IdentityServer durante il processo di autenticazione deve essere incluso nella richiesta, come illustrato nell'esempio di codice seguente:

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

Il token di accesso viene archiviato come impostazione dell'applicazione e viene recuperato dalla risorsa di archiviazione specifica della piattaforma e incluso nella chiamata al GetOrderAsync metodo nella OrderService classe .

Analogamente, il token di accesso deve essere incluso quando si inviano dati a un'API protetta IdentityServer, come illustrato nell'esempio di codice seguente:

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

Il token di accesso viene recuperato dalla risorsa di archiviazione specifica della piattaforma e incluso nella chiamata al UpdateBasketAsync metodo nella BasketService classe .

La RequestProvider classe, nell'app per dispositivi mobili eShopOnContainers, usa la HttpClient classe per effettuare richieste alle API RESTful esposte dall'applicazione di riferimento eShopOnContainers. Quando si effettuano richieste alle API di ordinamento e carrello, che richiedono l'autorizzazione, è necessario includere un token di accesso valido nella richiesta. A tale scopo, aggiungere il token di accesso alle intestazioni dell'istanza HttpClient , come illustrato nell'esempio di codice seguente:

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

La proprietà DefaultRequestHeaders della classe HttpClient espone le intestazioni inviate a ogni richiesta e il token di accesso viene aggiunto all'intestazione Authorization preceduta dalla stringa Bearer. Quando la richiesta viene inviata a un'API RESTful, il valore dell'intestazione Authorization viene estratto e convalidato per assicurarsi che venga inviato da un emittente attendibile e usato per determinare se l'utente dispone dell'autorizzazione per richiamare l'API che la riceve.

Per altre informazioni su come l'app per dispositivi mobili eShopOnContainers effettua richieste Web, vedere Accesso ai dati remoti.

Riepilogo

Esistono molti approcci per l'integrazione dell'autenticazione e dell'autorizzazione in un'app Xamarin.Forms che comunica con un'applicazione Web MVC ASP.NET. L'app per dispositivi mobili eShopOnContainers esegue l'autenticazione e l'autorizzazione con un microservizio di identità in contenitori che usa IdentityServer 4. IdentityServer è un framework OpenID Connect open source e OAuth 2.0 per ASP.NET Core che si integra con ASP.NET Core Identity per eseguire l'autenticazione del token di connessione.

L'app per dispositivi mobili richiede token di sicurezza da IdentityServer, per l'autenticazione di un utente o per l'accesso a una risorsa. Quando si accede a una risorsa, è necessario includere un token di accesso nella richiesta alle API che richiedono l'autorizzazione. Il middleware di IdentityServer convalida i token di accesso in ingresso per assicurarsi che vengano inviati da un'autorità di certificazione attendibile e che siano validi per essere usati con l'API che li riceve.