Authentification et autorisation

Remarque

Ce livre électronique a été publié au printemps 2017 et n’a pas été mis à jour depuis. Il y a beaucoup dans le livre qui reste précieux, mais certains de la matière est obsolète.

L’authentification est le processus d’obtention des informations d’identification telles que le nom et le mot de passe d’un utilisateur et la validation de ces informations d’identification par rapport à une autorité. Si les informations d’identification sont valides, l’entité qui a envoyé les informations d’identification est considérée comme une identité authentifiée. Une fois qu’une identité a été authentifiée, un processus d’autorisation détermine si cette identité a accès à une ressource donnée.

Il existe de nombreuses approches pour intégrer l’authentification et l’autorisation dans une Xamarin.Forms application qui communique avec une application web MVC ASP.NET, notamment l’utilisation d’ASP.NET Core Identity, de fournisseurs d’authentification externes tels que Microsoft, Google, Facebook ou Twitter et l’intergiciel d’authentification. L’application mobile eShopOnContainers effectue l’authentification et l’autorisation avec un microservice d’identité conteneurisé qui utilise IdentityServer 4. L’application mobile demande des jetons de sécurité à partir de IdentityServer, soit pour l’authentification d’un utilisateur, soit pour accéder à une ressource. Pour que IdentityServer émette des jetons pour le compte d’un utilisateur, l’utilisateur doit se connecter à IdentityServer. Toutefois, IdentityServer ne fournit pas d’interface utilisateur ou de base de données pour l’authentification. Par conséquent, dans l’application de référence eShopOnContainers, ASP.NET Core Identity est utilisé à cet effet.

Authentification

L’authentification est requise lorsqu’une application doit connaître l’identité de l’utilisateur actuel. Le mécanisme principal d’identification des utilisateurs d’ASP.NET Core est le système d’appartenance ASP.NET Core Identity, qui stocke les informations utilisateur dans une banque de données configurée par le développeur. En règle générale, ce magasin de données est un magasin EntityFramework, bien que des magasins personnalisés ou des packages tiers puissent être utilisés pour stocker des informations d’identité dans le stockage Azure, Azure Cosmos DB ou d’autres emplacements.

Pour les scénarios d’authentification qui utilisent un magasin de données utilisateur local et qui conservent les informations d’identité entre les requêtes via des cookies (comme c’est le cas dans ASP.NET applications web MVC), ASP.NET Core Identity est une solution appropriée. En revanche, dans d’autres scénarios, il n’est pas toujours commun de conserver et de transmettre les données au moyen de cookies. Par exemple, une application web ASP.NET Core qui expose des points de terminaison RESTful accessibles à partir d’une application mobile doit généralement utiliser l’authentification par jeton du porteur, car les cookies ne peuvent pas être utilisés dans ce scénario. Toutefois, les jetons du porteur peuvent facilement être récupérés et inclus dans l’en-tête d’autorisation des demandes web effectuées à partir de l’application mobile.

Émission de jetons du porteur à l’aide de IdentityServer 4

IdentityServer 4 est une infrastructure Code source ouvert OpenID Connecter et OAuth 2.0 pour ASP.NET Core, qui peut être utilisée pour de nombreux scénarios d’authentification et d’autorisation, notamment l’émission de jetons de sécurité pour les utilisateurs locaux ASP.NET Core Identity.

Remarque

OpenID Connect et OAuth 2.0 sont très similaires, tout en ayant des responsabilités différentes.

OpenID Connect est une couche d’authentification basée sur le protocole OAuth 2.0. OAuth 2 est un protocole qui permet aux applications de demander des jetons d’accès à un service de jetons de sécurité et de les utiliser pour communiquer avec les API. Cette délégation réduit la complexité des applications clientes et des API, car l’authentification et l’autorisation peuvent être centralisées.

La combinaison d’OpenID Connecter et OAuth 2.0 combine les deux problèmes de sécurité fondamentaux de l’authentification et de l’accès à l’API, et IdentityServer 4 est une implémentation de ces protocoles.

Dans les applications qui utilisent une communication directe client-à-microservice, comme l’application de référence eShopOnContainers, un microservice d’authentification dédié agissant en tant que service STS (Security Token Service) peut être utilisé pour authentifier les utilisateurs, comme illustré dans la figure 9-1. Pour plus d’informations sur la communication directe entre les clients et les microservices, consultez Communication Between Client and Microservices.

Authentication by a dedicated authentication microservice

Figure 9-1 : Authentification par un microservice d’authentification dédié

L’application mobile eShopOnContainers communique avec le microservice d’identité, qui utilise IdentityServer 4 pour effectuer l’authentification et le contrôle d’accès pour les API. Par conséquent, l’application mobile demande des jetons à partir de IdentityServer, soit pour authentifier un utilisateur, soit pour accéder à une ressource :

  • L’authentification des utilisateurs avec IdentityServer est obtenue par l’application mobile demandant un jeton d’identité, qui représente le résultat d’un processus d’authentification. Au minimum, il contient un identificateur pour l’utilisateur et des informations sur la façon et l’authentification de l’utilisateur. Il peut également contenir des données d’identité supplémentaires.
  • L’accès à une ressource avec IdentityServer est obtenu par l’application mobile demandant un jeton d’accès, ce qui permet d’accéder à une ressource d’API. Les clients demandent des jetons d’accès et les transfèrent à l’API. Les jetons d’accès contiennent des informations sur le client et l’utilisateur (le cas échéant). Les API utilisent ensuite ces informations pour autoriser l’accès à leurs données.

Remarque

Un client doit être inscrit auprès de IdentityServer pour pouvoir demander des jetons.

Ajout de IdentityServer à une application web

Pour qu’une application web ASP.NET Core utilise IdentityServer 4, elle doit être ajoutée à la solution Visual Studio de l’application web. Pour plus d’informations, consultez Vue d’ensemble de la documentation IdentityServer.

Une fois IdentityServer inclus dans la solution Visual Studio de l’application web, elle doit être ajoutée au pipeline de traitement des requêtes HTTP de l’application web, afin qu’elle puisse traiter les requêtes aux points de terminaison OpenID Connecter et OAuth 2.0. Cela se fait dans la méthode Configure de la classe Startup de l’application web, comme illustré dans l’exemple de code suivant :

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

L’ordre est important dans le pipeline de traitement des requêtes HTTP de l’application web. Par conséquent, IdentityServer doit être ajouté au pipeline avant l’infrastructure d’interface utilisateur qui implémente l’écran de connexion.

Configuration d’IdentityServer

IdentityServer doit être configuré dans la ConfigureServices méthode de la classe de Startup l’application web en appelant la services.AddIdentityServer méthode, comme illustré dans l’exemple de code suivant de l’application de référence 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>();  
}

Après avoir appelé la méthode services.AddIdentityServer, des API Fluent supplémentaires sont appelées pour configurer les éléments suivants :

  • Informations d’identification utilisées pour la signature.
  • Ressources d’API et d’identité auxquelles les utilisateurs peuvent demander l’accès.
  • Les clients appelés à se connecter pour demander des jetons.
  • Identité ASP.NET Core.

Conseil

Chargez dynamiquement la configuration IdentityServer 4. Les API d’IdentityServer 4 permettent de configurer IdentityServer à partir d’une liste en mémoire d’objets de configuration. Dans l’application de référence eShopOnContainers, ces collections en mémoire sont codées en dur dans l’application. Toutefois, dans les scénarios de production, elles peuvent être chargées dynamiquement à partir d’un fichier de configuration ou d’une base de données.

Pour plus d’informations sur la configuration d’IdentityServer pour utiliser ASP.NET Core Identity, consultez Utilisation d’ASP.NET Core Identity dans la documentation IdentityServer.

Configuration des ressources d’API

Lors de la configuration des ressources d’API, la méthode AddInMemoryApiResources attend une collection de IEnumerable<ApiResource>. L’exemple de code suivant montre la méthode GetApis qui fournit cette collection dans l’application de référence eShopOnContainers :

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

Cette méthode spécifie qu’IdentityServer doit protéger les API de commandes et de panier. Par conséquent, les jetons d’accès managé IdentityServer sont requis lors de l’appel à ces API. Pour plus d’informations sur le type ApiResource, consultez Ressource d’API dans la documentation IdentityServer 4.

Configuration des ressources d’identité

Lors de la configuration des ressources d’identité, la méthode AddInMemoryIdentityResources attend une collection de IEnumerable<IdentityResource>. Les ressources d’identité sont des données comme l’ID utilisateur, le nom ou l’adresse e-mail. Chaque ressource d’identité a un nom unique et des types de revendications arbitraires peuvent lui être attribués, ce qui sera ensuite inclus dans le jeton d’identité de l’utilisateur. L’exemple de code suivant montre la méthode GetResources qui fournit cette collection dans l’application de référence eShopOnContainers :

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

La spécification OpenID Connect spécifie certaines ressources d’identité standard. La condition minimale est que la prise en charge soit fournie pour l’émission d’un ID unique pour les utilisateurs. Pour ce faire, exposez la ressource d’identité IdentityResources.OpenId.

Remarque

La IdentityResources classe prend en charge toutes les étendues définies dans la spécification openID Connecter (openid, e-mail, profil, téléphone et adresse).

IdentityServer prend également en charge la définition de ressources d’identité personnalisées. Pour plus d’informations sur le IdentityResource type, consultez la ressource Identity dans la documentation IdentityServer 4.

Configuration des clients

Les clients sont des applications qui peuvent demander des jetons à IdentityServer. En règle générale, les paramètres suivants doivent être définis au minimum pour chaque client :

  • ID client unique.
  • Interactions autorisées avec le service de jeton (type d’autorisation).
  • Emplacement où les jetons d’identité et d’accès sont envoyés (URI de redirection).
  • Liste des ressources auxquelles le client est autorisé à accéder (étendues).

Lors de la configuration des clients, la méthode AddInMemoryClients attend une collection de IEnumerable<Client>. L’exemple de code suivant montre la configuration de l’application mobile eShopOnContainers dans la GetClients méthode qui fournit cette collection dans l’application de référence 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
        },
        ...
    };
}

Cette configuration spécifie les données pour les propriétés suivantes :

  • ClientId: ID unique pour le client.
  • ClientName: nom complet du client, utilisé pour la journalisation et l’écran de consentement.
  • AllowedGrantTypes: spécifie la façon dont un client souhaite interagir avec IdentityServer. Pour plus d’informations, consultez Configuration du flux d’authentification.
  • ClientSecrets: spécifie les informations d’identification de clé secrète client utilisées lors de la demande de jetons à partir du point de terminaison de jeton.
  • RedirectUris: spécifie les URI autorisés auxquels retourner des jetons ou des codes d’autorisation.
  • RequireConsent: spécifie si un écran de consentement est requis.
  • RequirePkce: spécifie si les clients utilisant un code d’autorisation doivent envoyer une clé de preuve.
  • PostLogoutRedirectUris: spécifie les URI autorisés à rediriger vers une date de déconnexion.
  • AllowedCorsOrigins: spécifie l’origine du client afin que IdentityServer puisse autoriser les appels d’origine croisée à partir de l’origine.
  • AllowedScopes: spécifie les ressources auxquelles le client a accès. Par défaut, un client n’a accès à aucune ressource.
  • AllowOfflineAccess: spécifie si le client peut demander des jetons d’actualisation.

Configuration du flux d’authentification

Le flux d’authentification entre un client et IdentityServer peut être configuré en spécifiant les types d’octroi dans la propriété Client.AllowedGrantTypes. Les spécifications openID Connecter et OAuth 2.0 définissent un certain nombre de flux d’authentification, notamment :

  • Implicite. Ce flux est optimisé pour les applications basées sur un navigateur, et doit être utilisé soit pour l’authentification utilisateur uniquement, soit pour les demandes d’authentification et de jeton d’accès. Tous les jetons sont transmis via le navigateur et, par conséquent, les fonctionnalités avancées comme les jetons d’actualisation ne sont pas autorisées.
  • Code d’autorisation. Ce flux permet de récupérer des jetons sur un canal d’arrière-plan, par opposition au canal frontal du navigateur, tout en prenant en charge l’authentification du client.
  • Hybride. Ce flux est une combinaison des types d’octroi de code implicite et d’autorisation. Le jeton d’identité est transmis via le canal du navigateur et contient la réponse du protocole signé avec d’autres artefacts tels que le code d’autorisation. Une fois la réponse validée, le canal principal doit être utilisé pour récupérer l’accès et le jeton d’actualisation.

Conseil

Utilisez le flux d’authentification hybride. Le flux d’authentification hybride atténue un certain nombre d’attaques qui s’appliquent au canal du navigateur. Il s’agit du flux recommandé pour les applications natives qui souhaitent récupérer des jetons d’accès (et éventuellement actualiser des jetons).

Pour plus d’informations sur les flux d’authentification, consultez Types d’autorisation dans la documentation IdentityServer 4.

Exécution de l’authentification

Pour que IdentityServer émette des jetons pour le compte d’un utilisateur, l’utilisateur doit se connecter à IdentityServer. Toutefois, IdentityServer ne fournit pas d’interface utilisateur ou de base de données pour l’authentification. Par conséquent, dans l’application de référence eShopOnContainers, ASP.NET Core Identity est utilisé à cet effet.

L’application mobile eShopOnContainers s’authentifie auprès de IdentityServer avec le flux d’authentification hybride, illustré dans la figure 9-2.

High-level overview of the sign-in process

Figure 9-2 : Vue d’ensemble générale du processus de connexion

Une demande de connexion est adressée à <base endpoint>:5105/connect/authorize. Une fois l’authentification réussie, IdentityServer retourne une réponse d’authentification contenant un code d’autorisation et un jeton d’identité. Le code d’autorisation est ensuite envoyé à <base endpoint>:5105/connect/token, qui répond avec les jetons d’accès, d’identité et d’actualisation.

L’application mobile eShopOnContainers se déconnecte de IdentityServer en envoyant une demande à <base endpoint>:5105/connect/endsession, avec des paramètres supplémentaires. Une fois la déconnexion terminée, IdentityServer répond en envoyant un URI de redirection post-déconnexion à l’application mobile. La figure 9-3 illustre ce processus.

High-level overview of the sign-out process

Figure 9-3 : Vue d’ensemble générale du processus de déconnexion

Dans l’application mobile eShopOnContainers, la communication avec IdentityServer est effectuée par la IdentityService classe, qui implémente l’interface IIdentityService . Cette interface spécifie que la classe d’implémentation doit fournir des méthodes CreateAuthorizationRequest, CreateLogoutRequest et GetTokenAsync.

Connexion

Lorsque l’utilisateur appuie sur le bouton LOGIN sur le LoginView, le SignInCommand dans la LoginViewModel classe est exécuté, ce qui exécute à son tour la SignInAsync méthode. L’exemple de code suivant illustre cette méthode :

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

Cette méthode appelle la CreateAuthorizationRequest méthode dans la IdentityService classe, qui est illustrée dans l’exemple de code suivant :

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

Cette méthode crée l’URI pour le point de terminaison d’autorisation identityServer, avec les paramètres requis. Le point de terminaison d’autorisation se trouve à /connect/authorize sur le port 5105 du point de terminaison de base exposé en tant que paramètre utilisateur. Pour plus d’informations sur les paramètres utilisateur, consultez Gestion de la configuration.

Remarque

La surface d’attaque de l’application mobile eShopOnContainers est réduite en implémentant l’extension Proof Key for Code Exchange (PKCE) sur OAuth. PKCE protège le code d’autorisation d’être utilisé s’il est intercepté. Pour ce faire, le client génère un vérificateur de secrets, dont un hachage est passé dans la demande d’autorisation et qui est présenté sans hachage lors de l’utilisation du code d’autorisation. Pour plus d’informations sur PKCE, consultez Proof Key for Code Exchange by OAuth Public Clients sur le site web Internet Engineering Task Force.

L’URI retourné est stocké dans la propriété LoginUrl de la classe LoginViewModel. Lorsque la IsLogin propriété devient true, l’in WebView the LoginView devient visible. Les WebView données lient sa Source propriété à la LoginUrl propriété de la LoginViewModel classe, et effectue ainsi une demande de connexion à IdentityServer lorsque la LoginUrl propriété est définie sur le point de terminaison d’autorisation d’IdentityServer. Lorsque IdentityServer reçoit cette demande et que l’utilisateur n’est pas authentifié, il WebView est redirigé vers la page de connexion configurée, qui est affichée dans la figure 9-4.

Login page displayed by the WebView

Figure 9-4 : Page de connexion affichée par le WebView

Une fois la connexion terminée, la WebView est redirigée vers un URI de retour. Cette navigation WebView entraîne l’exécution de la méthode NavigateAsync dans la classe LoginViewModel, comme illustré dans l’exemple de code suivant :

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

Cette méthode analyse la réponse d’authentification contenue dans l’URI de retour et, à condition qu’un code d’autorisation valide soit présent, il envoie une demande au point de terminaison du jeton IdentityServer, en passant le code d’autorisation, le vérificateur de secret PKCE et d’autres paramètres requis. Le point de terminaison de jeton se trouve à /connect/token sur le port 5105 du point de terminaison de base exposé en tant que paramètre utilisateur. Pour plus d’informations sur les paramètres utilisateur, consultez Gestion de la configuration.

Conseil

Valider les URI de retour. Bien que l’application mobile eShopOnContainers ne valide pas l’URI de retour, la meilleure pratique consiste à vérifier que l’URI de retour fait référence à un emplacement connu pour empêcher les attaques de redirection ouverte.

Si le point de terminaison de jeton reçoit un code d’autorisation valide et un vérificateur de secret PKCE, il répond avec un jeton d’accès, un jeton d’identité et un jeton d’actualisation. Le jeton d’accès (qui autorise l’accès aux ressources d’API) et le jeton d’identité sont ensuite stockés en tant que paramètres d’application, et la navigation de page est effectuée. Par conséquent, l’effet global dans l’application mobile eShopOnContainers est le suivant : à condition que les utilisateurs puissent s’authentifier avec IdentityServer avec succès, ils accèdent à la MainView page, qui est un TabbedPage qui affiche l’onglet CatalogView sélectionné.

Pour plus d’informations sur la navigation de page, consultez Navigation. Pour plus d’informations sur la façon dont WebView la navigation entraîne l’exécution d’une méthode de modèle d’affichage, consultez Appel de la navigation à l’aide de comportements. Pour plus d’informations sur les paramètres d’application, consultez Configuration Management.

Remarque

EShopOnContainers autorise également une connexion factice lorsque l’application est configurée pour utiliser des services fictifs dans le SettingsView. Dans ce mode, l’application ne communique pas avec IdentityServer, ce qui permet à l’utilisateur de se connecter à l’aide des informations d’identification.

Déconnexion

Lorsque l’utilisateur appuie sur le bouton LOG OUT dans le ProfileView, le LogoutCommand dans la ProfileViewModel classe est exécuté, ce qui exécute à son tour la LogoutAsync méthode. Cette méthode effectue la navigation de page vers la page LoginView, en passant un jeu d’instances LogoutParameter à true en tant que paramètre. Pour plus d’informations sur le passage de paramètres pendant la navigation de page, consultez Passage de paramètres pendant la navigation.

Lorsqu’une vue est créée et accédée, la méthode InitializeAsync du modèle d’affichage associé de la vue est exécutée ; elle exécute ensuite la méthode Logout de la classe LoginViewModel, comme illustré dans l’exemple de code suivant :

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

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

Cette méthode appelle la méthode CreateLogoutRequest dans la classe IdentityService, en passant le jeton d’identité récupéré à partir des paramètres d’application en tant que paramètre. Pour plus d’informations sur les paramètres d’application, consultez Configuration Management. L’exemple de code suivant montre la méthode 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);  
}

Cette méthode crée l’URI vers le point de terminaison de session final de IdentityServer, avec les paramètres requis. Le point de terminaison de session de fin se trouve à /connect/endsession sur le port 5105 du point de terminaison de base exposé en tant que paramètre utilisateur. Pour plus d’informations sur les paramètres utilisateur, consultez Gestion de la configuration.

L’URI retourné est stocké dans la propriété LoginUrl de la classe LoginViewModel. Pendant que la IsLogin propriété est true, la WebViewLoginView propriété est visible. Les WebView données lient sa Source propriété à la LoginUrl propriété de la LoginViewModel classe, et effectue ainsi une demande de déconnexion à IdentityServer lorsque la LoginUrl propriété est définie sur le point de terminaison de session final de IdentityServer. Lorsque IdentityServer reçoit cette requête, à condition que l’utilisateur soit connecté, la déconnexion se produit. L’authentification est suivie avec un cookie géré par l’intergiciel d’authentification des cookies à partir d’ASP.NET Core. Par conséquent, la déconnexion de IdentityServer supprime le cookie d’authentification et envoie un URI de redirection post-déconnexion au client.

Dans l’application mobile, vous WebView êtes redirigé vers l’URI de redirection post-déconnexion. Cette navigation WebView entraîne l’exécution de la méthode NavigateAsync dans la classe LoginViewModel, comme illustré dans l’exemple de code suivant :

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

Cette méthode efface à la fois le jeton d’identité et le jeton d’accès à partir des paramètres d’application, et définit la IsLogin propriété falsesur , ce qui entraîne l’invisible de la WebViewLoginView page. Enfin, la propriété LoginUrl est définie sur l’URI du point de terminaison d’autorisation IdentityServer, avec les paramètres requis, en préparation de la prochaine fois que l’utilisateur lance une connexion.

Pour plus d’informations sur la navigation de page, consultez Navigation. Pour plus d’informations sur la façon dont WebView la navigation entraîne l’exécution d’une méthode de modèle d’affichage, consultez Appel de la navigation à l’aide de comportements. Pour plus d’informations sur les paramètres d’application, consultez Configuration Management.

Remarque

EShopOnContainers autorise également une déconnexion simulée lorsque l’application est configurée pour utiliser des services fictifs dans le Paramètres View. Dans ce mode, l’application ne communique pas avec IdentityServer et efface les jetons stockés des paramètres de l’application.

Autorisation

Après l’authentification, ASP.NET API web Core doivent souvent autoriser l’accès, ce qui permet à un service de rendre les API accessibles à certains utilisateurs authentifiés, mais pas à tous.

La restriction de l’accès à un itinéraire MVC core ASP.NET peut être obtenue en appliquant un attribut Authorize à un contrôleur ou une action, ce qui limite l’accès au contrôleur ou à l’action aux utilisateurs authentifiés, comme illustré dans l’exemple de code suivant :

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

Si un utilisateur non autorisé tente d’accéder à un contrôleur ou à une action marqué avec l’attribut Authorize , l’infrastructure MVC retourne un code d’état HTTP 401 (non autorisé).

Remarque

Les paramètres peuvent être spécifiés sur l’attribut Authorize pour restreindre une API à des utilisateurs spécifiques. Pour plus d’informations, consultez Autorisation.

IdentityServer peut être intégré au workflow d’autorisation afin que les jetons d’accès qu’il fournit contrôlent l’autorisation. Cette approche est illustrée dans la figure 9-5.

Authorization by access token

Figure 9-5 : Autorisation par jeton d’accès

L’application mobile eShopOnContainers communique avec le microservice d’identité et demande un jeton d’accès dans le cadre du processus d’authentification. Le jeton d’accès est ensuite transféré aux API exposées par les microservices de classement et de panier dans le cadre des demandes d’accès. Les jetons d’accès contiennent des informations sur le client et l’utilisateur. Les API utilisent ensuite ces informations pour autoriser l’accès à leurs données. Pour plus d’informations sur la configuration de IdentityServer pour protéger les API, consultez Configuration des ressources d’API.

Configuration de IdentityServer pour effectuer une autorisation

Pour effectuer l’autorisation avec IdentityServer, son intergiciel d’autorisation doit être ajouté au pipeline de requêtes HTTP de l’application web. L’intergiciel est ajouté dans la méthode dans la ConfigureAuth classe de Startup l’application web, qui est appelée à partir de la Configure méthode, et est illustrée dans l’exemple de code suivant de l’application de référence eShopOnContainers :

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

Cette méthode garantit que l’API n’est accessible qu’avec un jeton d’accès valide. L’intergiciel valide le jeton entrant pour s’assurer qu’il est envoyé à partir d’un émetteur approuvé et vérifie que le jeton est valide pour être utilisé avec l’API qui la reçoit. Par conséquent, l’accès au contrôleur de commande ou de panier retourne un code d’état HTTP 401 (non autorisé), indiquant qu’un jeton d’accès est requis.

Remarque

Le middleware d’autorisation d’IdentityServer doit être ajouté au pipeline de requête HTTP de l’application web avant d’ajouter le MVC avec app.UseMvc() ou app.UseMvcWithDefaultRoute().

Effectuer des demandes d’accès aux API

Lorsque vous effectuez des demandes aux microservices de commande et de panier, le jeton d’accès obtenu à partir de IdentityServer pendant le processus d’authentification doit être inclus dans la requête, comme indiqué dans l’exemple de code suivant :

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

Le jeton d’accès est stocké en tant que paramètre d’application et est récupéré à partir d’un stockage spécifique à la plateforme et inclus dans l’appel à la GetOrderAsync méthode dans la OrderService classe.

De même, le jeton d’accès doit être inclus lors de l’envoi de données à une API protégée par IdentityServer, comme indiqué dans l’exemple de code suivant :

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

Le jeton d’accès est récupéré à partir d’un stockage spécifique à la plateforme et inclus dans l’appel à la UpdateBasketAsync méthode dans la BasketService classe.

La RequestProvider classe, dans l’application mobile eShopOnContainers, utilise la HttpClient classe pour effectuer des requêtes aux API RESTful exposées par l’application de référence eShopOnContainers. Lorsque vous effectuez des requêtes pour les API de commande et de panier, qui nécessitent une autorisation, un jeton d’accès valide doit être inclus avec la demande. Pour ce faire, ajoutez le jeton d’accès aux en-têtes de l’instance HttpClient , comme illustré dans l’exemple de code suivant :

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

La propriété DefaultRequestHeaders de la classe HttpClient expose les en-têtes envoyés avec chaque requête, et le jeton d’accès est ajouté à l’en-tête Authorization précédé de la chaîne Bearer. Lorsque la demande est envoyée à une API RESTful, la valeur de l’en-tête Authorization est extraite et validée pour s’assurer qu’elle est envoyée à partir d’un émetteur approuvé et utilisée pour déterminer si l’utilisateur a l’autorisation d’appeler l’API qui la reçoit.

Pour plus d’informations sur la façon dont l’application mobile eShopOnContainers effectue des requêtes web, consultez Accès aux données distantes.

Résumé

Il existe de nombreuses approches pour intégrer l’authentification et l’autorisation dans une Xamarin.Forms application qui communique avec une application web ASP.NET MVC. L’application mobile eShopOnContainers effectue l’authentification et l’autorisation avec un microservice d’identité conteneurisé qui utilise IdentityServer 4. IdentityServer est un framework OpenID Connect et OAuth 2.0 open source pour ASP.NET Core qui s’intègre à ASP.NET Core Identity pour effectuer l’authentification par jeton du porteur.

L’application mobile demande des jetons de sécurité à partir de IdentityServer, soit pour l’authentification d’un utilisateur, soit pour accéder à une ressource. Lors de l’accès à une ressource, un jeton d’accès doit être inclus dans la requête aux API qui nécessitent une autorisation. L’intergiciel IdentityServer valide les jetons d’accès entrants pour s’assurer qu’ils sont envoyés à partir d’un émetteur approuvé et qu’ils sont valides pour être utilisés avec l’API qui les reçoit.