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 Connect 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 Connect et OAuth 2.0 combine les deux problèmes de sécurité fondamentaux de l’authentification et de l’accès aux 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.
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 Connect 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 Connect (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 Connect 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.
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.
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.
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 WebView
LoginView
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é false
sur , ce qui entraîne l’invisible de la WebView
LoginView
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 SettingsView. 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.
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.