[Actualité] IdentityServer4 : Autoriser l’application MVC à accéder à l’API, via le jeton obtenu du STS
par
, 25/03/2019 à 04h00 (9012 Affichages)
IdentityServer est une solution open source .NET de gestion d’identité et de contrôle d’accès. Il repose sur les protocoles OpenID Connect et OAuth 2.0.
IdentityServer peut être utilisé par les entreprises pour mettre en place une solution pour :
- la protection de leurs ressources ;
- l’authentification des utilisateurs via une base de données ou des fournisseurs externes d’identité (Microsoft, Google, Facebook, etc.) ;
- la gestion des sessions et la fédération (single sign-on) ;
- la génération des jetons pour les clients ;
- la validation des jetons et bien plus.
Ce billet est le sixième que j’écris sur le sujet. Les billets précédents ont porté sur les points suivants :
Mise en place d’un STS avec IdentityServer4 pour sécuriser ses applications .NET
Sécurisation d’une Web API ASP.NET Core avec le STS IdentityServer4
IdentityServer4 : création et configuration du Client pour accéder à une Web API ASP.NET Core sécurisée
IdentityServer4 : Authentification d’un utilisateur avec OpenID Connect
IdentityServer4 : création et configuration d’un client utilisant OpenID Connect
Dans le billet précédent sur le sujet, nous avons développé un client MVC capable d’utiliser IdentityServer et OpenID Connect pour s’authentifier via un formulaire et obtenir l’accès aux ressources sécurisées. Nous voulons maintenant qu’une fois l’utilisateur authentifié, ce dernier puisse obtenir un jeton d’accès pour appeler l’API que nous avons développée précédemment.
IdentityServer implémente le protocole OAuth 2.0 pour la gestion des jetons. Nous aurons donc recours à cette étape à un mode hybride qui utilise à la fois OpenID Connect et OAUth 2.0. Voyons comment procéder.
Modification de la configuration du client
Dans l’application IdentityServer, nous allons modifier la configuration de l’application MVC dans le fichier Config.cs. La nouvelle configuration est la suivante :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 // OpenID Connect implicit flow client (MVC) new Client { ClientId = "mvcappclient", ClientName = "MVC Client", AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, RequireConsent = false, RedirectUris = { "https://localhost:5005/signin-oidc" }, PostLogoutRedirectUris = { "https://localhost:5005/signout-callback-oidc" }, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "testapi" }, AllowOfflineAccess = true }
Vous allez remarquer que nous avons changé le GrantTypes de « Implicit » à « HybridAndClientCredentials ». Le mode implicite est pratique pour la transmission des jetons d’identification via le navigateur. Par contre, en ce qui concerne les jetons d’accès (dont nous aurons besoin pour accéder à l’API), qui sont plus sensibles que les jetons d’identification, ce mode est moins pratique. Pour pallier à cela, un mode hybride est offert.
Le mode hybride permet au client d’obtenir dans un premier temps un jeton d’identification qui est transmis par le navigateur. Une fois l’authenticité du jeton validé, le client ouvre un canal de retour avec IdentityServer pour obtenir un jeton d’accès.
Nous avons ensuite fourni un mot de passe (ClientSecrets) qui sera utilisé pour fournir le jeton d’accès via le canal de retour.
Enfin, nous avons ajouté l’API dans les scopes afin que le client puisse accéder à ce dernier et mettre « AllowOfflineAccess » à « True ». Cela permet de demander l’actualisation des jetons pour des accès de longue durée aux APIs.
C’est tout ce qui est à modifier coté IdentityServer.
Installation du package IdentityModel
La première chose à faire côté client est l’installation du package IdentityModel dans l’application MVC. Il s’agit de la librairie utilisée côté client pour accéder facilement au « discovery endpoint » d’IdentityServer.
Modification de la configuration de l’authentification
Nous devons modifier la méthode ConfigureServices du fichier Startup.cs et remplacer le code de la configuration de l’authentification par ce qui suit :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "https://localhost:5001"; options.RequireHttpsMetadata = false; options.ClientId = "mvcappclient"; options.ClientSecret = "secret"; options.ResponseType = "code id_token"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("testapi"); options.Scope.Add("offline_access"); });
Nous avons ajouté le ClientSecret afin qu’il puisse correspondre à la valeur définie dans IdentityServer. Nous avons également ajouté l’ID de l’API (testapi) et « offline_access » dans les scopes pour avoir les mêmes niveaux d’accès des deux côtés. La valeur « code id_token » pour le champ ResponseType permet de spécifier que nous utilisons un mode hybride.
Nous pouvons utiliser deux approches pour appeler l’API, selon nos besoins.
Appel de l'API via un justificatif d’Identité (credential) du client
Maintenant que le client à des justificatifs d’identité (ClientSecret) pour s’identifier, il peut utiliser ces informations pour s’identifier auprès d’IdentityServer et obtenir un jeton d’accès qu’il pourra utiliser pour appeler l’API. Le code pour effectuer cela est le suivant :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 public async Task<IActionResult> CallApiUsingClientCredentials() { var tokenClient = new TokenClient("https://localhost:5001/connect/token", "mvcappclient", "secret"); var tokenResponse = await tokenClient.RequestClientCredentialsAsync("testapi"); var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var content = await client.GetStringAsync("https://localhost:5003/api/secure"); ViewBag.Json = JArray.Parse(content).ToString(); return View(); }
Ajoutez celui-ci comme méthode d’action du HomeController, puis ajouter la vue correspondante dans le dossier Views/Home avec le code suivant :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 @{ ViewData["Title"] = "CallApiUsingClientCredentials"; } <h2>API response</h2> <pre>@ViewBag.Json</pre>
Pour tester l’application, vous devez exécuter à la fois les trois applications (IdentityServer, TestAPI et le client MVC). Une fois les applications en cours d’exécution, utilisez le lien suivant pour visualiser les résultats :
https://localhost:5005/home/CallApiU...entCredentials
Appel de l'API via un jeton d’accès
Dans la seconde approche, le client devra d’abord s’authentifier par formulaire en utilisant OpenID Connect. Il recevra ensuite un jeton d’accès qu’il pourra utiliser pour accéder à l’API. Le code correspondant est le suivant :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 public async Task<IActionResult> CallApiUsingUserAccessToken() { var accessToken = await HttpContext.GetTokenAsync("access_token"); var client = new HttpClient(); client.SetBearerToken(accessToken); var content = await client.GetStringAsync("https://localhost:5003/api/secure"); ViewBag.Json = JArray.Parse(content).ToString(); return View(); }
Ce mode est pratique si on a besoin que l’utilisateur soit identifié avant de pouvoir accéder à l’API. Vous pouvez ajouter la vue correspondante et effectuer vos tests.
Dans le prochain billet, nous verrons comment au lieu d'utiliser l'authentification par formulaire, nous pouvons plutôt utiliser un provider d’authentification tiers, notamment un compte Microsoft pour l'authentification.