Blog ENI : Toute la veille numérique !
Offre estivale️ ☀️ : de -20% à -30% sur les livres en ligne et vidéos, avec le code PLAGE Cliquez ici !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. OAuth 2 et OpenID Connect
  3. Backend For Frontend (BFF) Framework
Extrait - OAuth 2 et OpenID Connect Sécurisez vos applications .Net avec IdentityServer
Extraits du livre
OAuth 2 et OpenID Connect Sécurisez vos applications .Net avec IdentityServer Revenir à la page d'achat du livre

Backend For Frontend (BFF) Framework

Présentation

Le Backend For Frontend (BFF) est une mécanique de sécurité pour les applications SPA JavaScript ou Blazor WebAssembly servies par un backend ASP.Net Core. Cela permet de déporter la gestion OAuth/OIDC depuis l’application front-end vers le back-end. Il y a deux bénéfices à cette mécanique : la sécurité d’une part et contourner les restrictions grandissantes des navigateurs concernant les cookies qui nuisent de plus en plus au bon fonctionnement des flux d’authentification.

Côté sécurité : en utilisant le BFF, les tokens ne sont plus stockés côté client dans le local storage du navigateur, mais côté serveur ce qui réduit considérablement le risque de se faire dérober ceux-ci. Les sessions sont gérées au travers de cookies cryptés et « HTTP only » comme cela pouvait être le cas avant avec les sites web classiques.

Côté données privées : les navigateurs limitent de plus en plus l’utilisation des cookies tiers car ceux-ci sont à la base des systèmes de tracking et de publicité qui sont aujourd’hui dans le collimateur. Google a annoncé vouloir se débarrasser définitivement des cookies tiers et ils sont en bonne voie pour y parvenir. Le problème...

Backend

1. Mise en place d’une application Web API

Pour commencer à utiliser le BFF, il nous faut déjà un back-end qui aille de pair avec un front-end. Dans notre solution, l’application Blazor WebAssembly n’a pas de back-end, nous allons donc lui en créer un pour l’occasion.

Ajoutez un projet ASP.NET Core Web API nommé BlazorWasmClientApplicationBackend.

images/14EI001.png

Une fois le projet créé, ajoutez le projet BlazorWasmClientApplication dans les projets référencés par le back-end.

Faites un clic droit sur le nom du projet - Add - Project reference :

images/14EI002.png

Dans le fichier Program.cs du back-end, modifiez la séquence des middlewares comme ceci :

var app = builder.Build();  
  
f (app.Environment.IsDevelopment())  
{  
    app.UseSwagger();  
    app.UseSwaggerUI();  
}  
app.UseHttpsRedirection();  
app.UseBlazorFrameworkFiles();  
app.UseStaticFiles();  
app.UseRouting();  
app.UseAuthentication();  
app.UseAuthorization();  
app.MapControllers();  
app.MapFallbackToFile("index.html");  
  
app.Run(); 

Il faudra également ajouter le package NuGet :

Microsoft.AspNetCore.Components.WebAssembly.Server 

Et modifier le fichier launchsettings.json du backend pour que l’application démarre sur le même port que celui défini pour l’application cliente. Ce n’est pas gênant car ensuite nous ne démarrerons plus directement l’application cliente, celle-ci sera servie par le back-end :

{  
  "$schema": "https://json.schemastore.org/launchsettings.json", 
  "profiles": {  
    "https": {  
      "commandName": "Project",  
      "dotnetRunMessages": true,  
      "launchBrowser": true,  
      "launchUrl": "swagger",  
      "applicationUrl": "https://localhost:5007",  
      "environmentVariables":...

Client

Le serveur est maintenant prêt. Le client, de son côté, utilise toujours la configuration Open ID Connect. Il faut changer ceci pour utiliser à la place l’authentification via le BFF.

Dans notre application WebAssembly, nous avions intégré l’authentification Open ID Connect via la méthode :

builder.Services.AddOidcAuthentication(options => {  
  
  options.ProviderOptions.Authority = "https://localhost:5000"; 
  options.ProviderOptions.ClientId = "DC2A2D6F1B5A4A19A496ED6BEA9C761C"; 
  options.ProviderOptions.ResponseType = OpenIdConnectResponseType.Code; 
  options.ProviderOptions.DefaultScopes.Clear();  
 
options.ProviderOptions.DefaultScopes.Add(OpenIdConnectScope.OpenIdProfile); 
    options.ProviderOptions.DefaultScopes.Add(OpenIdConnectScope.Email); 
  
options.ProviderOptions.DefaultScopes.Add(OpenIdConnectScope.OfflineAccess); 
  options.ProviderOptions.DefaultScopes.Add("books.read");  
  options.ProviderOptions.DefaultScopes.Add("books.write");  
  options.UserOptions.NameClaim= "name";  
  options.UserOptions.RoleClaim = "role";  
}); 

Cette méthode par appels successifs à des "sous méthodes" déclenche la liste suivante d’injections :

services.TryAddEnumerable(ServiceDescriptor. 
Scoped<IPostConfigureOptions<RemoteAuthenticationOptions
<OidcProviderOptions>>, DefaultOidcOptionsConfiguration>());  
  
services.AddOptions();  
  
services.AddAuthorizationCore();  
  
services.TryAddScoped<AuthenticationStateProvider,  
RemoteAuthenticationService<TRemoteAuthenticationState, 
TAccount, TProviderOptions>>();  
 AddAuthenticationStateProvider<TRemoteAuthenticationState> 
(services);  
  
services.TryAddTransient<BaseAddressAuthorizationMessageHandler> 
();  
  
services.TryAddTransient<AuthorizationMessageHandler>();  
 
services.TryAddScoped(sp =>  
{  
  return (IAccessTokenProvider)sp. 
GetRequiredService<AuthenticationStateProvider>();  ...

Consommation d’APIS

Nous sommes maintenant connectés à notre application via le BFF, c’est une première étape. Nous devons maintenant gérer l’utilisation des API. En mode OIDC, l’application faisait une requête à notre API en fournissant son token et tout fonctionnait. Maintenant, notre application cliente n’a qu’un cookie qui ne peut être utilisé que par le BFF. Cela a forcément une incidence sur l’utilisation de nos API.

On peut distinguer deux cas de figure :

  • l’API est une API « locale », c’est-à-dire qu’elle fait partie du BFF ;

  • l’API est une API distante. Dans ce cas, l’API est une autre application, peut-être une application tierce, qui n’a pas de lien avec le BFF.

1. API locales

Le cas le plus simple est le cas des API locales. Le projet du BFF est basé sur le template de base d’API de Microsoft, il y a donc le célèbre WeatherForecast. Nous allons utiliser cet exemple pour notre API.

Dans l’application WebAssembly, le fichier FetchData.razor contient le code suivant :

@code {  
private WeatherForecast[]? forecasts;  
  
protected override async Task OnInitializedAsync()  
{  
  forecasts = await Http.GetFromJsonAsync
<WeatherForecast[]>("sample-data/weather.json");  ...