Partager via


Sécuriser un ASP.NET Core Blazor Web App avec l’ID Microsoft Entra

Cet article explique comment sécuriser un Blazor Web App Microsoft avec la plateforme d'identité Microsoft et des packages Web Microsoft Identity pour Microsoft Entra ID en utilisant une application exemple.

Cette version de l’article traite de l’implémentation d’Entra sans adopter le modèle backend pour le serveur frontal (BFF). Le modèle BFF est pratique pour faire des requêtes authentifiées auprès de services externes. Remplacez le sélecteur de version d’article par modèle BFF si la spécification de l’application appelle à adopter le modèle BFF.

La spécification suivante est couverte :

  • Le Blazor Web App utilise le mode de rendu automatique avec interactivité globale (InteractiveAuto).
  • Le projet serveur appelle AddAuthenticationStateSerialization pour ajouter un fournisseur d’état d’authentification côté serveur qui utilise PersistentComponentState pour transmettre l’état d’authentification au client. Le client appelle AddAuthenticationStateDeserialization pour désérialiser et utiliser l'état d'authentification transmis par le serveur. L’état d’authentification est fixe pour la durée de vie de l’application WebAssembly.
  • L'application utilise Microsoft Entra ID, basé sur les packages Web de MicrosoftIdentity.
  • L’actualisation automatique des jetons non interactifs est gérée par l’infrastructure.
  • L’application utilise des abstractions de service côté serveur et côté client pour afficher les données météorologiques générées :
    • Lors du rendu du composant Weather sur le serveur pour afficher les données météorologiques, le composant utilise le ServerWeatherForecaster. Les packages web Microsoft Identity fournissent une API pour créer un service web nommé en aval pour effectuer des appels d’API web. IDownstreamApi est injecté dans le ServerWeatherForecaster, qui est utilisé pour appeler CallApiForUserAsync pour obtenir des données météorologiques à partir d’une API web externe (MinimalApiJwt projet).
    • Lorsque le Weather composant est rendu sur le client, le composant utilise l’implémentation ClientWeatherForecaster du service, qui utilise un fichier préconfiguré HttpClient (dans le fichier du Program projet client) pour effectuer un appel d’API web à l’API minimale (/weather-forecast) du projet serveur pour les données météorologiques. Le point de terminaison d’API minimal obtient les données météorologiques de la ServerWeatherForecaster classe et les retourne au client pour le rendu par le composant.

Exemple de solution

L’exemple de solution se compose des projets suivants :

  • BlazorWebAppEntra : projet côté serveur de l’Blazor Web App, contenant un exemple de point de terminaison d’API minimale pour des données météorologiques.
  • BlazorWebAppEntra.Client : Projet côté client de la Blazor Web App.
  • MinimalApiJwt : API web back-end, contenant un exemple de point de terminaison d’API minimale pour les données météorologiques.

Accédez à l’exemple via le dossier de la dernière version dans le répertoire des échantillons Blazor avec le lien suivant. L’exemple se trouve dans le dossier BlazorWebAppEntra pour .NET 9 ou version ultérieure.

Démarrez la solution à partir du Aspire/Aspire.AppHost projet.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Enregistrements d'applications Microsoft Entra ID

Nous vous recommandons d’utiliser des inscriptions distinctes pour les applications et les API web, même lorsque les applications et les API web se trouvent dans la même solution. Les instructions suivantes concernent l’application BlazorWebAppEntra et l’API web MinimalApiJwt de l’exemple de solution, mais les mêmes conseils s’appliquent généralement aux inscriptions basées sur Entra pour les applications et les API web.

Inscrivez d’abord l’API web (MinimalApiJwt) afin que vous puissiez ensuite accorder l’accès à l’API web lors de l’inscription de l’application. L’ID de locataire et l’ID client de l’API web sont utilisés pour configurer l’API web dans son Program fichier. Après avoir inscrit l’API web, exposez l’API web dans les enregistrements> d’applicationsExposez une API avec un nom d’étendue de Weather.Get. Enregistrez l’URI d’ID d’application à utiliser dans la configuration de l’application.

Ensuite, inscrivez l’application (BlazorWebAppEntra) avec une configuration de plateforme Web et un Redirect URI de https://localhost/signin-oidc (un port n’est pas obligatoire). L'ID de locataire, le domaine de locataire et l'ID client de l'application, ainsi que l'adresse de base de l'API web, l'URI d'ID d'application et le nom de l'étendue météorologique, sont utilisés pour configurer l'application dans son fichier appsettings.json. Accordez l'autorisation API pour accéder à l'API web dans les inscriptions d'applications>autorisations d'API. Si la spécification de sécurité de l’application l’appelle, vous pouvez accorder au administrateur le consentement de l’organisation pour accéder à l’API web. Les utilisateurs et groupes autorisés sont affectés à l'inscription de l'application dans les inscriptions d'application et les applications d'entreprise.

Dans la configuration de l'inscription d'applications du portail Entra ou Azure pour les flux d'autorisation implicite et hybrides, ne cochez aucune case pour le point de terminaison d'autorisation renvoyant des Jetons d'accès ou des Jetons d'identité. Le gestionnaire OpenID Connect demande automatiquement les jetons appropriés à l’aide du code retourné par le point de terminaison d’autorisation.

Créez une clé secrète client dans l’inscription de l’application dans le portail Entra ou Azure (Gérer les>certificats et secrets>Nouveau secret client). Conservez le secret client Valeur pour l'utiliser dans la section suivante.

Des instructions supplémentaires sur la configuration d’Entra pour des paramètres spécifiques sont fournies plus loin dans cet article.

Projet côté serveur Blazor Web App (BlazorWebAppEntra)

Le projet BlazorWebAppEntra est le projet côté serveur de l’Blazor Web App.

Projet Blazor Web App côté client (BlazorWebAppEntra.Client)

Le projet BlazorWebAppEntra.Client est le projet côté client de l’Blazor Web App.

Si l’utilisateur doit se connecter ou sortir pendant le rendu côté client, un rechargement de page complet est lancé.

Projet d’API web back-end (MinimalApiJwt)

Le projet MinimalApiJwt est une API web back-end pour plusieurs projets front-end. Le projet configure un point de terminaison d’API minimale pour les données météorologiques.

Le fichier MinimalApiJwt.http peut être utilisé pour tester la requête de données météorologiques. Notez que le projet MinimalApiJwt doit être en cours d’exécution pour tester le point de terminaison et que le point de terminaison est codé en dur dans le fichier. Pour en savoir plus, reportez-vous à Utiliser des fichiers .http dans Visual Studio 2022.

Le projet inclut des packages et une configuration pour produire des documents OpenAPI et l’interface utilisateur Swagger dans l’environnement de développement. Pour plus d’informations, consultez Utiliser les documents OpenAPI générés.

Un point de terminaison de données de prévision météorologique sécurisé se trouve dans le fichier du Program projet :

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

La méthode d’extension RequireAuthorization nécessite une autorisation pour la définition de route. Pour les contrôleurs que vous ajoutez au projet, ajoutez l’attribut [Authorize] au contrôleur ou à l’action.

Configurer le projet d’API web back-end (MinimalApiJwt)

Configurez le projet dans l’appel JwtBearerOptionsAddJwtBearer dans le MinimalApiJwt fichier du Program projet.

Pour l’inscription de l’application API web, l’étendue Weather.Get est configurée dans le portail Entra ou Azure dans Exposer une API.

Authority définit l’autorité pour effectuer des appels OIDC.

jwtOptions.Authority = "{AUTHORITY}";

Les exemples suivants utilisent un ID de locataire de aaaabbbb-0000-cccc-1111-dddd2222eeee.

Si l’application est enregistrée dans un locataire ME-ID, l’autorité doit correspondre à l’émetteur (iss) du JWT retourné par le fournisseur d’identité :

jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";

Si l'application est enregistrée dans un locataire AAD B2C :

jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";

Audience définit l’audience pour tout jeton d’accès JWT reçu.

jwtOptions.Audience = "{AUDIENCE}";

Faire correspondre la valeur uniquement au chemin de l’URI d’ID d’application configuré lors de l’ajout de l’étendue Weather.Get sous Exposer une API dans le portail Entra ou Azure. N’incluez pas le nom de l’étendue , «Weather.Get », dans la valeur.

Les exemples suivants utilisent un ID d’application (client) de 11112222-bbbb-3333-cccc-4444dddd5555. Le deuxième exemple utilise un domaine locataire de contoso.onmicrosoft.com.

exemple de locataire ME-ID :

jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";

Exemple de locataire AAD B2C :

jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4444dddd5555";

Configurer le projet de serveur (BlazorWebAppEntra)

AddMicrosoftIdentityWebAppà partir de Microsoft Identity Web (Microsoft.Identity.Web package NuGet, documentation de l’API) est configuré dans le BlazorWebAppEntra fichier du Program projet.

Obtenez l’ID d’application (client), le domaine de locataire (éditeur) et l’ID d’annuaire (locataire) de l’application à partir de l’inscription de l’application dans le portail Entra ou Azure. L’URI d’ID d’application est obtenue à partir de l’inscription de l’API web pour l’étendue Weather.Get. N’incluez pas le nom d’étendue lorsque vous prenez l’URI de l'ID de l'application à partir du portail.

Dans le fichier BlazorWebAppEntra du projet Program, indiquez les valeurs des espaces réservés ci-dessous dans la configuration web de Microsoft Identity :

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.Domain = "{DIRECTORY NAME}.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "{TENANT ID}";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ];
    })
    .AddDistributedTokenCaches();

Espaces réservés dans la configuration précédente :

  • {CLIENT ID (BLAZOR APP)}: ID d’application (client).
  • {DIRECTORY NAME}: nom du répertoire du domaine du locataire (éditeur).
  • {TENANT ID} : ID d’annuaire (locataire).
  • {BASE ADDRESS}: adresse de base de l’API web.
  • {APP ID URI}: URI de l'ID de l'application pour les scopes d'API web. L’un des formats suivants est utilisé, où l’espace {CLIENT ID (WEB API)} réservé est l’ID client de l’inscription Entra de l’API web, et l’espace {DIRECTORY NAME} réservé est le nom du répertoire du domaine client (éditeurs) (exemple : contoso).
    • format de locataire ME-ID : api://{CLIENT ID (WEB API)}
    • Format de locataire B2C : https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Exemple :

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.Domain = "contoso.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "aaaabbbb-0000-cccc-1111-dddd2222eeee";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
    })
    .AddDistributedTokenCaches();

Cette version de l’article traite de l’implémentation d’Entra avec le modèle Back-end pour le serveur frontal (BFF). Modifiez le sélecteur de version d’article en modèle Non-BFF si la spécification de l’application n’appelle pas l’adoption du modèle BFF.

La spécification suivante est couverte :

  • Le Blazor Web App utilise le mode de rendu automatique avec interactivité globale (InteractiveAuto).
  • Le projet serveur appelle AddAuthenticationStateSerialization pour ajouter un fournisseur d’état d’authentification côté serveur qui utilise PersistentComponentState pour transmettre l’état d’authentification au client. Le client appelle AddAuthenticationStateDeserialization pour désérialiser et utiliser l'état d'authentification transmis par le serveur. L’état d’authentification est fixe pour la durée de vie de l’application WebAssembly.
  • L'application utilise Microsoft Entra ID, basé sur les packages Web de MicrosoftIdentity.
  • L’actualisation automatique des jetons non interactifs est gérée par l’infrastructure.
  • Le modèle BFF (Backend for Frontend) est adopté en utilisant .NET Aspire pour la découverte de services et YARP pour proxyser les requêtes vers un point de terminaison de prévision météorologique sur l’application back-end.
    • Une API Web dorsale utilise l'authentification par porteur JWT pour valider les jetons JWT enregistrés par Blazor Web App lors de la connexion cookie.
    • Aspire améliore l’expérience de création d’applications natives Cloud .NET. Il fournit un ensemble cohérent et validé d’outils et de modèles pour la création et l’exécution d’applications distribuées.
    • YARP (Yet Another Reverse Proxy) est une bibliothèque utilisée pour créer un serveur proxy inverse.
  • L’application utilise des abstractions de service côté serveur et côté client pour afficher les données météorologiques générées.
    • Lors du rendu du composant Weather sur le serveur pour afficher les données météorologiques, le composant utilise le ServerWeatherForecaster. Les packages web Microsoft Identity fournissent une API pour créer un service web nommé en aval pour effectuer des appels d’API web. IDownstreamApi est injecté dans le ServerWeatherForecaster, qui est utilisé pour appeler CallApiForUserAsync pour obtenir des données météorologiques à partir d’une API web externe (MinimalApiJwt projet).
    • Lorsque le Weather composant est rendu sur le client, le composant utilise l’implémentation ClientWeatherForecaster du service, qui utilise un fichier préconfiguré HttpClient (dans le fichier du Program projet client) pour effectuer un appel d’API web à l’API minimale (/weather-forecast) du projet serveur pour les données météorologiques. L'endpoint d'API minimal obtient un jeton d'accès pour l'utilisateur en appelant GetAccessTokenForUserAsync. En plus des portées correctes, un appel de proxy inverse est effectué vers l’API web externe (MinimalApiJwt projet) pour obtenir et retourner des données météorologiques au client pour être rendu par le composant.

Pour plus d’informations sur .NET Aspire, consultez Disponibilité générale de .NET Aspire : simplifier le développement .NET cloud natif (mai 2024).

Conditions préalables

.NET Aspire nécessite la version 17.10 de Visual Studio ou une version ultérieure

Consultez également la section Prérequis du guide de démarrage rapide : Créer votre première .NET Aspire application.

Exemple de solution

L’exemple de solution se compose des projets suivants :

  • .NET Aspire:
    • Aspire.AppHost: permet de gérer les problèmes d’orchestration de haut niveau de l’application.
    • Aspire.ServiceDefaults : contient les configurations d’application .NET Aspire par défaut, qui peuvent être étendues et personnalisées en fonction des besoins.
  • MinimalApiJwt : API web back-end, contenant un exemple de point de terminaison d’API minimale pour les données météorologiques.
  • BlazorWebAppEntra: Projet côté serveur du Blazor Web App.
  • BlazorWebAppEntra.Client : Projet côté client de la Blazor Web App.

Accédez à l’exemple via le dossier de la dernière version dans le répertoire des échantillons Blazor avec le lien suivant. L’exemple se trouve dans le dossier BlazorWebAppEntraBff pour .NET 9 ou version ultérieure.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Enregistrements d'applications Microsoft Entra ID

Nous vous recommandons d’utiliser des inscriptions distinctes pour les applications et les API web, même lorsque les applications et les API web se trouvent dans la même solution. Les instructions suivantes concernent l’application BlazorWebAppEntra et l’API web MinimalApiJwt de l’exemple de solution, mais les mêmes conseils s’appliquent généralement aux inscriptions basées sur Entra pour les applications et les API web.

Inscrivez d’abord l’API web (MinimalApiJwt) afin que vous puissiez ensuite accorder l’accès à l’API web lors de l’inscription de l’application. L’ID de locataire et l’ID client de l’API web sont utilisés pour configurer l’API web dans son Program fichier. Après avoir inscrit l’API web, exposez l’API web dans les enregistrements> d’applicationsExposez une API avec un nom d’étendue de Weather.Get. Enregistrez l’URI d’ID d’application à utiliser dans la configuration de l’application.

Ensuite, inscrivez l’application (BlazorWebAppEntra) avec une configuration de plateforme Web et un Redirect URI de https://localhost/signin-oidc (un port n’est pas obligatoire). L'ID de locataire, le domaine de locataire et l'ID client de l'application, ainsi que l'adresse de base de l'API web, l'URI d'ID d'application et le nom de l'étendue météorologique, sont utilisés pour configurer l'application dans son fichier appsettings.json. Accordez l'autorisation API pour accéder à l'API web dans les inscriptions d'applications>autorisations d'API. Si la spécification de sécurité de l’application l’appelle, vous pouvez accorder au administrateur le consentement de l’organisation pour accéder à l’API web. Les utilisateurs et groupes autorisés sont affectés à l'inscription de l'application dans les inscriptions d'application et les applications d'entreprise.

Dans la configuration de l'inscription d'applications du portail Entra ou Azure pour les flux d'autorisation implicite et hybrides, ne cochez aucune case pour le point de terminaison d'autorisation renvoyant des Jetons d'accès ou des Jetons d'identité. Le gestionnaire OpenID Connect demande automatiquement les jetons appropriés à l’aide du code retourné par le point de terminaison d’autorisation.

Créez une clé secrète client dans l’inscription de l’application dans le portail Entra ou Azure (Gérer les>certificats et secrets>Nouveau secret client). Conservez le secret client Valeur pour l'utiliser dans la section suivante.

Des instructions supplémentaires sur la configuration d’Entra pour des paramètres spécifiques sont fournies plus loin dans cet article.

.NET Aspire projets

Pour plus d’informations sur l’utilisation de .NET Aspire et des détails sur les projets .AppHost et .ServiceDefaults de l’exemple d’application, consultez la documentation .NET Aspire.

Vérifiez que vous avez satisfait aux prérequis pour .NET Aspire. Pour plus d’informations, consultez la section Prérequis de Démarrage rapide : créer votre première application .NET Aspire.

L’exemple d’application configure uniquement un profil de lancement HTTP non sécurisé (http) à utiliser pendant les tests de développement. Pour plus d’informations, notamment un exemple de profils de paramètres de lancement non sécurisés et sécurisés, consultez Autoriser le transport non sécurisé dans .NET Aspire (documentation .NET Aspire).

Projet côté serveur Blazor Web App (BlazorWebAppEntra)

Le projet BlazorWebAppEntra est le projet côté serveur de l’Blazor Web App.

Projet Blazor Web App côté client (BlazorWebAppEntra.Client)

Le projet BlazorWebAppEntra.Client est le projet côté client de l’Blazor Web App.

Si l’utilisateur doit se connecter ou sortir pendant le rendu côté client, un rechargement de page complet est lancé.

Projet d’API web back-end (MinimalApiJwt)

Le projet MinimalApiJwt est une API web back-end pour plusieurs projets front-end. Le projet configure un point de terminaison d’API minimale pour les données météorologiques. Les requêtes provenant du projet côté serveur d’Blazor Web App (BlazorWebAppEntra) sont proxysées vers le projet MinimalApiJwt.

Le fichier MinimalApiJwt.http peut être utilisé pour tester la requête de données météorologiques. Notez que le projet MinimalApiJwt doit être en cours d’exécution pour tester le point de terminaison et que le point de terminaison est codé en dur dans le fichier. Pour en savoir plus, reportez-vous à Utiliser des fichiers .http dans Visual Studio 2022.

Le projet inclut des packages et une configuration pour produire des documents OpenAPI et l’interface utilisateur Swagger dans l’environnement de développement. Pour plus d’informations, consultez Utiliser les documents OpenAPI générés.

Un point de terminaison de données de prévision météorologique sécurisé se trouve dans le fichier du Program projet :

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

La méthode d’extension RequireAuthorization nécessite une autorisation pour la définition de route. Pour les contrôleurs que vous ajoutez au projet, ajoutez l’attribut [Authorize] au contrôleur ou à l’action.

Configurer le projet d’API web back-end (MinimalApiJwt)

Configurez le MinimalApiJwt projet dans le JwtBearerOptions de l'appel AddJwtBearer dans le fichier Program du projet.

Pour l’inscription de l’application API web, l’étendue Weather.Get est configurée dans le portail Entra ou Azure dans Exposer une API.

Authority définit l’autorité pour effectuer des appels OIDC.

jwtOptions.Authority = "{AUTHORITY}";

Les exemples suivants utilisent un ID de locataire de aaaabbbb-0000-cccc-1111-dddd2222eeee.

Si l’application est enregistrée dans un locataire ME-ID, l’autorité doit correspondre à l’émetteur (iss) du JWT retourné par le fournisseur d’identité :

jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";

Si l'application est enregistrée dans un locataire AAD B2C :

jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";

Audience définit l’audience pour tout jeton d’accès JWT reçu.

jwtOptions.Audience = "{AUDIENCE}";

Faire correspondre la valeur uniquement au chemin de l’URI d’ID d’application configuré lors de l’ajout de l’étendue Weather.Get sous Exposer une API dans le portail Entra ou Azure. N’incluez pas le nom de l’étendue , «Weather.Get », dans la valeur.

Les exemples suivants utilisent un ID d’application (client) de 11112222-bbbb-3333-cccc-4444dddd5555. Le deuxième exemple utilise un domaine locataire de contoso.onmicrosoft.com.

exemple de locataire ME-ID :

jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";

Exemple de locataire AAD B2C :

jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4444dddd5555";

Configurer le projet de serveur (BlazorWebAppEntra)

AddMicrosoftIdentityWebAppà partir de Microsoft Identity Web (Microsoft.Identity.Web package NuGet, documentation de l’API) est configuré dans le BlazorWebAppEntra fichier du Program projet.

Obtenez l’ID d’application (client), le domaine de locataire (éditeur) et l’ID d’annuaire (locataire) de l’application à partir de l’inscription de l’application dans le portail Entra ou Azure. L’URI d’ID d’application est obtenue à partir de l’inscription de l’API web pour l’étendue Weather.Get. N’incluez pas le nom d’étendue lorsque vous prenez l’URI de l'ID de l'application à partir du portail.

Dans le fichier BlazorWebAppEntra du projet Program, indiquez les valeurs des espaces réservés ci-dessous dans la configuration web de Microsoft Identity :

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.Domain = "{DIRECTORY NAME}.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "{TENANT ID}";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ];
    })
    .AddDistributedTokenCaches();

Espaces réservés dans la configuration précédente :

  • {CLIENT ID (BLAZOR APP)}: ID d’application (client).
  • {DIRECTORY NAME}: nom du répertoire du domaine du locataire (éditeur).
  • {TENANT ID} : ID d’annuaire (locataire).
  • {BASE ADDRESS}: adresse de base de l’API web.
  • {APP ID URI}: URI de l'ID de l'application pour les scopes d'API web. L’un des formats suivants est utilisé, où l’espace {CLIENT ID (WEB API)} réservé est l’ID client de l’inscription Entra de l’API web, et l’espace {DIRECTORY NAME} réservé est le nom du répertoire du domaine client (éditeurs) (exemple : contoso).
    • format de locataire ME-ID : api://{CLIENT ID (WEB API)}
    • Format de locataire B2C : https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Exemple :

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.Domain = "contoso.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "aaaabbbb-0000-cccc-1111-dddd2222eeee";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
    })
    .AddDistributedTokenCaches();

Avertissement

Les applications de production doivent utiliser un fournisseur de cache de jeton distribué de production. Sinon, l’application peut avoir des performances médiocres dans certains scénarios. Pour plus d’informations, consultez la section Utiliser un fournisseur de cache de jeton distribué de production .

Le chemin de rappel (CallbackPath) doit correspondre à l’URI de redirection (chemin de rappel de connexion) configuré lors de l’inscription de l’application dans l’Entra ou Portail Azure. Les chemins sont configurés dans le panneau d'authentification de l'inscription de l'application. La valeur par défaut de CallbackPath est /signin-oidc pour un URI de redirection inscrit https://localhost/signin-oidc (un port n’est pas obligatoire).

Le SignedOutCallbackPath est le chemin de requête au sein du chemin de base de l'application, intercepté par le gestionnaire OpenID Connect où l'agent utilisateur est d'abord renvoyé après s'être déconnecté de l'ID Entra. L’exemple d’application ne définit pas de valeur pour le chemin d’accès, car la valeur par défaut «/signout-callback-oidc» est utilisée. Après avoir intercepté la requête, le gestionnaire OpenID Connect redirige vers le SignedOutRedirectUri ou le RedirectUri, s’il est spécifié.

Configurez le chemin de rappel de sortie dans l'enregistrement Entra de l'application. Dans le portail Entra ou Azure, configurez le chemin dans les entrées Redirect URI de la configuration de la plateforme Web :

https://localhost/signout-callback-oidc

Remarque

Un port n’est pas requis pour les adresses localhost lors de l’utilisation d’Entra.

Si vous n'ajoutez pas l'URI du chemin de rappel signé à l'enregistrement de l'application dans Entra, Entra refuse de rediriger l'utilisateur vers l'application et lui demande simplement de fermer la fenêtre de son navigateur.

Remarque

Entra ne redirige pas un utilisateur administrateur principal (compte racine) ou un utilisateur externe vers l’application Blazor. Au lieu de cela, Entra consigne l’utilisateur hors de l’application et recommande de fermer toutes ses fenêtres de navigateur. Pour plus d'informations, consultez postLogoutRedirectUri not working when authority url contains a tenant ID (AzureAD/microsoft-authentication-library-for-js #5783).

Avertissement

Ne stockez pas les secrets d’application, les chaîne de connexion, les informations d’identification, les mots de passe, les numéros d’identification personnels (PIN), le code C#/.NET privé ou les clés/jetons privés dans le code côté client, qui est toujours non sécurisé. Dans les environnements de test/intermédiaire et de production, le code côté Blazor serveur et les API web doivent utiliser des flux d’authentification sécurisés qui évitent de conserver les informations d’identification dans le code du projet ou les fichiers de configuration. En dehors des tests de développement locaux, nous vous recommandons d’éviter l’utilisation de variables d’environnement pour stocker des données sensibles, car les variables d’environnement ne sont pas l’approche la plus sécurisée. Pour les tests de développement locaux, l’outil Secret Manager est recommandé pour sécuriser les données sensibles. Pour plus d’informations, consultez Gestion sécurisée des données sensibles et des informations d’identification.

Établir la clé secrète client

Cette section s’applique uniquement au projet serveur du Blazor Web App.

Utilisez l’une ou l’autre des approches suivantes pour fournir la clé secrète client à l’application :

  • Outil Secret Manager : l’outil Secret Manager stocke les données privées sur l’ordinateur local et est utilisé uniquement pendant le développement local.
  • Azure Key Vault : vous pouvez stocker la clé secrète client dans un coffre de clés à utiliser dans n’importe quel environnement, y compris pour l’environnement de développement lors de l’utilisation locale. Certains développeurs préfèrent utiliser des coffres-forts de clés pour les déploiements intermédiaires et de production, et l’outil Secret Manager pour le développement local.

Nous vous recommandons vivement d’éviter de stocker les secrets client dans le code du projet ou les fichiers de configuration. Utilisez des flux d’authentification sécurisés, tels que l’une ou l’autre des approches de cette section.

Outil Gestionnaire de secrets

L’outil Gestionnaire de secrets peut stocker la clé secrète client de l’application serveur sous la clé AzureAd:ClientSecretde configuration.

L’application Blazor serveur n’a pas été initialisée pour l’outil Gestionnaire de secrets. Utilisez un interpréteur de commandes, tel que l’interpréteur de commandes Developer PowerShell dans Visual Studio, pour exécuter la commande suivante. Avant d’exécuter la commande, changez de répertoire pour le projet de serveur avec la commande cd. La commande établit un identificateur de secrets utilisateur (<UserSecretsId>) dans le fichier projet de l’application serveur, qui est utilisé en interne par l’outil pour suivre les secrets de l’application :

dotnet user-secrets init

Exécutez la commande suivante pour définir le secret client. L’espace réservé {SECRET} est la clé secrète client obtenue à partir de l’inscription Entra de l’application :

dotnet user-secrets set "AzureAd:ClientSecret" "{SECRET}"

Si vous utilisez Visual Studio, vous pouvez vérifier que le secret est défini en cliquant avec le bouton droit sur le projet de serveur dans Explorateur de solutions et en sélectionnant Gérer les secrets utilisateur.

Azure Key Vault

Azure Key Vault offre une approche sécurisée pour fournir la clé secrète client de l’application à l’application.

Pour créer un coffre de clés et définir une clé secrète client, consultez À propos des secrets Azure Key Vault (documentation Azure), qui relient les ressources pour commencer à utiliser Azure Key Vault. Pour implémenter le code de cette section, enregistrez l’URI du coffre de clés et le nom du secret à partir d’Azure lorsque vous créez le coffre de clés et le secret. Lorsque vous définissez la stratégie d’accès pour le secret dans le volet Stratégies d’accès :

  • Seule l’autorisation Obtenir le secret est requise.
  • Sélectionnez l’application comme Principal pour le secret.

Importante

Une clé secrète du coffre-fort est créée avec une date d'expiration. Veillez à suivre la date d'expiration d'un secret de Key Vault et à créer un nouveau secret pour l'application avant que celle-ci n'expire.

Ajoutez la classe AzureHelper suivante au projet de serveur. La méthode GetKeyVaultSecret récupère un secret à partir d'un coffre de clés. Ajustez l’espace de noms (BlazorSample.Helpers) pour qu’il corresponde au schéma d’espace de noms de votre projet.

Helpers/AzureHelper.cs :

using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

namespace BlazorWebAppEntra.Helpers;

public static class AzureHelper
{
    public static string GetKeyVaultSecret(string tenantId, string vaultUri, string secretName)
    {
        DefaultAzureCredentialOptions options = new()
        {
            // Specify the tenant ID to use the dev credentials when running the app locally
            // in Visual Studio.
            VisualStudioTenantId = tenantId,
            SharedTokenCacheTenantId = tenantId
        };

        var client = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential(options));
        var secret = client.GetSecretAsync(secretName).Result;

        return secret.Value.Value;
    }
}

Où les services sont inscrits dans le fichier du Program projet de serveur, obtenez et appliquez la clé secrète client à l’aide du code suivant :

var tenantId = builder.Configuration.GetValue<string>("AzureAd:TenantId")!;
var vaultUri = builder.Configuration.GetValue<string>("AzureAd:VaultUri")!;
var secretName = builder.Configuration.GetValue<string>("AzureAd:SecretName")!;

builder.Services.Configure<MicrosoftIdentityOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
    {
        options.ClientSecret = 
            AzureHelper.GetKeyVaultSecret(tenantId, vaultUri, secretName);
    });

Si vous souhaitez contrôler l’environnement dans lequel le code précédent fonctionne, par exemple pour éviter d’exécuter le code localement, car vous avez choisi d’utiliser l’outil Gestionnaire de secrets pour le développement local, vous pouvez encapsuler le code précédent dans une instruction conditionnelle qui vérifie l’environnement :

if (!context.HostingEnvironment.IsDevelopment())
{
    ...
}

Dans la section AzureAd de appsettings.json, ajoutez les clés et valeurs de configuration VaultUri et SecretName suivantes :

"VaultUri": "{VAULT URI}",
"SecretName": "{SECRET NAME}"

Dans l'exemple précédent :

  • L'espace réservé {VAULT URI} est l’URI du coffre de clés. Assurez-vous de saisir la barre oblique finale dans l'URI.
  • L’espace réservé {SECRET NAME} est le nom du secret.

Exemple :

"VaultUri": "https://contoso.vault.azure.net/",
"SecretName": "BlazorWebAppEntra"

La configuration est utilisée pour faciliter l’approvisionnement de coffres de clés dédiés et de noms de secrets en fonction des fichiers de configuration environnementaux de l’application. Par exemple, vous pouvez fournir différentes valeurs de configuration pour appsettings.Development.json le développement, appsettings.Staging.json lors de la préproduction et appsettings.Production.json pour le déploiement de production. Pour plus d’informations, consultez Configuration d’ASP.NET Core Blazor.

Sérialiser uniquement les revendications de nom et de rôle

Dans le Program fichier, toutes les revendications sont sérialisées en définissant SerializeAllClaims sur true. Si vous souhaitez uniquement que les revendications de nom et de rôle soient sérialisées pour CSR, supprimez l’option ou définissez-la sur false.

Fournir la configuration avec le fournisseur de configuration JSON (paramètres de l’application)

Les exemples de projets de solution configurent l’authentification du porteur Microsoft Identity Web et JWT dans leurs Program fichiers afin de rendre les paramètres de configuration détectables à l’aide de la saisie automatique C#. Les applications professionnelles utilisent généralement un fournisseur de configuration pour configurer des options OIDC, telles que le fournisseur de configuration JSON par défaut. Le fournisseur de configuration JSON charge la configuration à partir de fichiers appsettings.json/appsettings.{ENVIRONMENT}.jsonde paramètres d’application, où l’espace réservé est l’environnement {ENVIRONMENT}d’exécution de l’application. Suivez les instructions de cette section pour utiliser les fichiers de paramètres d’application pour la configuration.

Dans le fichier de paramètres de l’application (appsettings.json) du BlazorWebAppEntra projet, ajoutez la configuration JSON suivante :

{
  "AzureAd": {
    "CallbackPath": "/signin-oidc",
    "ClientId": "{CLIENT ID (BLAZOR APP)}",
    "Domain": "{DIRECTORY NAME}.onmicrosoft.com",
    "Instance": "https://login.microsoftonline.com/",
    "ResponseType": "code",
    "TenantId": "{TENANT ID}"
  },
  "DownstreamApi": {
    "BaseUrl": "{BASE ADDRESS}",
    "Scopes": [ "{APP ID URI}/Weather.Get" ]
  }
}

Mettez à jour les espaces réservés dans la configuration précédente pour qu’ils correspondent aux valeurs que l’application utilise dans le Program fichier :

  • {CLIENT ID (BLAZOR APP)}: ID d’application (client).
  • {DIRECTORY NAME}: nom du répertoire du domaine du locataire (éditeur).
  • {TENANT ID} : ID d’annuaire (locataire).
  • {BASE ADDRESS}: adresse de base de l’API web.
  • {APP ID URI}: URI de l'ID de l'application pour les scopes d'API web. L’un des formats suivants est utilisé, où l’espace {CLIENT ID (WEB API)} réservé est l’ID client de l’inscription Entra de l’API web, et l’espace {DIRECTORY NAME} réservé est le nom du répertoire du domaine client (éditeurs) (exemple : contoso).
    • format de locataire ME-ID : api://{CLIENT ID (WEB API)}
    • Format de locataire B2C : https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Exemple :

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "Domain": "contoso.onmicrosoft.com",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
},
"DownstreamApi": {
  "BaseUrl": "https://localhost:7277",
  "Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}

Mettez à jour toutes les autres valeurs de la configuration précédente pour qu’elles correspondent aux valeurs personnalisées/non par défaut utilisées dans le Program fichier.

La configuration est automatiquement récupérée par le générateur d’authentification.

Apportez les modifications suivantes dans le fichier Program :

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
-   .AddMicrosoftIdentityWebApp(msIdentityOptions =>
-   {
-       msIdentityOptions.CallbackPath = "...";
-       msIdentityOptions.ClientId = "...";
-       msIdentityOptions.Domain = "...";
-       msIdentityOptions.Instance = "...";
-       msIdentityOptions.ResponseType = "...";
-       msIdentityOptions.TenantId = "...";
-   })
+   .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
-   .AddDownstreamApi("DownstreamApi", configOptions =>
-   {
-       configOptions.BaseUrl = "...";
-       configOptions.Scopes = [ "..." ];
-   })
+   .AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
    .AddDistributedTokenCaches();

Remarque

Les applications de production doivent utiliser un fournisseur de cache de jeton distribué de production. Sinon, l’application peut avoir des performances médiocres dans certains scénarios. Pour plus d’informations, consultez la section Utiliser un fournisseur de cache de jeton distribué de production .

Dans le MinimalApiJwt projet, ajoutez la configuration des paramètres d’application suivante au appsettings.json fichier :

"Authentication": {
  "Schemes": {
    "Bearer": {
      "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/",
      "ValidAudiences": [ "{APP ID URI (WEB API)}" ]
    }
  }
},

Mettez à jour les espaces réservés dans la configuration précédente pour qu’ils correspondent aux valeurs que l’application utilise dans le Program fichier :

  • {TENANT ID (WEB API)}: ID de locataire de l’API web.
  • {APP ID URI (WEB API)}: URI d’ID d’application de l’API web.

Les formats d’autorité adoptent les modèles suivants :

  • ME-ID type de locataire : https://sts.windows.net/{TENANT ID}/
  • Type de locataire B2C : https://login.microsoftonline.com/{TENANT ID}/v2.0/

Les formats d’audience adoptent les modèles suivants ({CLIENT ID} est l’ID client de l’API web ; {DIRECTORY NAME} est le nom du répertoire, par exemple) contoso:

  • ME-ID type de locataire : api://{CLIENT ID}
  • Type de locataire B2C : https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}

La configuration est automatiquement récupérée par le générateur d’authentification du porteur JWT.

Supprimez les lignes suivantes du Program fichier :

- jwtOptions.Authority = "...";
- jwtOptions.Audience = "...";

Pour plus d’informations sur la configuration, consultez les ressources suivantes :

Utiliser un fournisseur de cache de jeton distribué de production

Les caches de jetons distribués en mémoire sont créés lors de l’appel AddDistributedTokenCaches pour vous assurer qu’il existe une implémentation de base disponible pour la mise en cache des jetons distribués.

Les applications web de production et les API web doivent utiliser un cache de jetons distribué de production (par exemple : Redis, Microsoft SQL Server, Microsoft Azure Cosmos DB).

Remarque

Pour le développement et le test locaux sur une seule machine, vous pouvez utiliser des caches de jetons en mémoire plutôt que des caches de jetons distribués :

builder.Services.AddInMemoryTokenCaches();

Plus loin dans la période de développement et de test, adoptez un fournisseur de cache de jetons distribués de production.

AddDistributedMemoryCache ajoute une implémentation par défaut de IDistributedCache qui stocke les éléments de cache en mémoire. Ceci est utilisé par Microsoft Identity Web pour la mise en cache des jetons.

Le cache de jetons distribués est configuré par MsalDistributedTokenCacheAdapterOptions:

  • Dans le cadre du développement à des fins de débogage, vous pouvez désactiver le cache L1 en définissant DisableL1Cache sur true. Assurez-vous de le remettre à false pour la production.
  • Définissez la taille maximale de votre cache L1CacheOptions.SizeLimit L1 pour empêcher le cache de dépasser la mémoire du serveur. La valeur par défaut est de 500 Mo.
  • Dans le cadre du développement à des fins de débogage, vous pouvez désactiver le chiffrement de jeton au repos en définissant Encrypt sur false, qui est la valeur par défaut. Assurez-vous de le remettre à true pour la production.
  • Définissez l’éviction du jeton du cache avec SlidingExpiration. La valeur par défaut est 1 heure.
  • Pour plus d’informations, notamment des conseils sur le rappel pour les échecs de cache L2 (OnL2CacheFailure) et les écritures asynchrones du cache L2 (EnableAsyncL2Write), consultez MsalDistributedTokenCacheAdapterOptions et sérialisation du cache de jeton : caches de jetons distribués.
builder.Services.AddDistributedMemoryCache();

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    options => 
    {
      // The following lines that are commented out reflect
      // default values. We recommend overriding the default
      // value of Encrypt to encrypt tokens at rest.

      //options.DisableL1Cache = false;
      //options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
      options.Encrypt = true;
      //options.SlidingExpiration = TimeSpan.FromHours(1);
    });

AddDistributedMemoryCache nécessite une référence au Microsoft.Extensions.Caching.Memory paquet NuGet.

Remarque

Pour obtenir des conseils sur l'ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Pour configurer un fournisseur de cache distribué de production, consultez La mise en cache distribuée dans ASP.NET Core.

Avertissement

Remplacez toujours les caches de jetons distribués en mémoire par un fournisseur de cache de jetons réel lors du déploiement de l’application dans un environnement de production. Si vous ne parvenez pas à adopter un fournisseur de cache de jeton distribué de production, l’application peut subir des performances considérablement dégradées.

Pour plus d’informations, consultez sérialisation du cache de jeton : Caches distribués. Toutefois, les exemples de code présentés ne s’appliquent pas aux applications ASP.NET Core, qui configurent les caches distribués via AddDistributedMemoryCache, et non AddDistributedTokenCache.

Utilisez un trousseau de clés de protection des données partagé en production afin que les instances de l’application dans une batterie de serveurs puissent déchiffrer les jetons lorsque MsalDistributedTokenCacheAdapterOptions.Encrypt est défini sur true.

Remarque

Pour le développement précoce et les tests locaux sur un seul ordinateur, vous pouvez définir Encryptfalse et configurer un anneau de clés de protection des données partagé ultérieurement :

options.Encrypt = false;

Plus loin dans la période de développement et de test, activez le chiffrement des jetons et adoptez un anneau de clés de protection des données partagé.

L’exemple suivant montre comment utiliser le Stockage Blob d'Azure et Azure Key Vault (PersistKeysToAzureBlobStorage/ProtectKeysWithAzureKeyVault) pour l’anneau de clés partagé. Les configurations de service sont des scénarios de cas de base à des fins de démonstration. Avant de déployer des applications de production, familiarisez-vous avec les services Azure et adoptez les meilleures pratiques à l’aide de leurs ensembles de documentation dédiés, qui sont répertoriés à la fin de cette section.

Vérifiez la présence des packages suivants dans le projet serveur du Blazor Web App:

Remarque

Pour obtenir des conseils sur l'ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Remarque

Avant de suivre les étapes suivantes, vérifiez que l’application est inscrite auprès de Microsoft Entra.

Le code suivant est généralement implémenté en même temps qu’un fournisseur de cache de jeton distribué de production est implémenté. D’autres options, à la fois dans Azure et en dehors d’Azure, sont disponibles pour gérer les clés de protection des données sur plusieurs instances d’application, mais l’exemple d’application montre comment utiliser les services Azure.

Configurez stockage Blob Azure pour conserver les clés de protection des données et les chiffrer au repos avec Azure Key Vault :

  • Créez un compte de stockage Azure. Le nom du compte dans l’exemple suivant est contoso.

  • Créez un conteneur pour contenir les clés de protection des données. Le nom du conteneur dans l’exemple suivant est data-protection.

  • Créez le fichier de clé sur votre ordinateur local. Dans l’exemple suivant, le fichier de clé est nommé keys.xml. Vous pouvez utiliser un éditeur de texte pour créer le fichier.

    keys.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <repository>
    </repository>
    
  • Chargez le fichier de clé (keys.xml) dans le conteneur du compte de stockage. Utilisez la commande Affichage/modification du menu contextuel à la fin de la ligne de clé dans le portail pour vérifier que l’objet blob contient le contenu précédent.

  • Utilisez la commande Generate SAS du menu contextuel pour obtenir l’URI de l’objet blob avec une signature d’accès partagé (SAP). Lorsque vous créez la SAS, utilisez les autorisations suivantes : Read, Add, Create, Write, Delete. L’URI est utilisé ultérieurement là où apparaît l’espace réservé {BLOB URI WITH SAS}.

Lors de l’établissement du coffre de clés dans le portail Entra ou Azure :

  • Configurez le coffre de clés pour utiliser une stratégie d’accès au coffre. Vérifiez que l’accès public à l’étape Réseau est activé (activé).

  • Dans le volet Stratégies d'accès, créez une nouvelle stratégie d'accès avec Get, Unwrap Key et Wrap Key les autorisations de clé. Sélectionnez l’application inscrite en tant que principal de service.

  • Lorsque le chiffrement de clé est actif, les clés du fichier de clé incluent le commentaire «This key is encrypted with Azure Key Vault. » Après avoir démarré l’application, sélectionnez la commande Affichage/modification dans le menu contextuel à la fin de la ligne de clé pour confirmer qu’une clé est présente avec la sécurité du coffre de clés appliquée.

Le AzureEventSourceLogForwarder service de l’exemple suivant transfère les messages de journalisation à partir du Kit de développement logiciel (SDK) Azure pour la journalisation et nécessite le Microsoft.Extensions.Azure package NuGet.

Remarque

Pour obtenir des conseils sur l'ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Au début du fichier Program, fournissez l'accès à l'API dans l'espace de noms Microsoft.Extensions.Azure.

using Microsoft.Extensions.Azure;

Utilisez le code suivant dans le Program fichier dans lequel les services sont inscrits :

builder.Services.TryAddSingleton<AzureEventSourceLogForwarder>();

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), new DefaultAzureCredential());

{BLOB URI WITH SAS}: URI complet où le fichier de clé doit être stocké avec le jeton SAP en tant que paramètre de chaîne de requête. L'URI est générée par Azure Storage lorsque vous demandez une SAS pour le fichier de clé téléchargé. Le nom du conteneur dans l’exemple suivant est data-protection, et le nom du compte de stockage est contoso. Le fichier de clé est nommé keys.xml.

Exemple :

https://contoso.blob.core.windows.net/data-protection/keys.xml?sp={PERMISSIONS}&st={START DATETIME}&se={EXPIRATION DATETIME}&spr=https&sv={STORAGE VERSION DATE}&sr=c&sig={TOKEN}

{KEY IDENTIFIER}: identificateur de clé Azure Key Vault utilisé pour le chiffrement de clé. Le nom du coffre de clés est contoso dans l'exemple suivant, et une stratégie d'accès permet à l'application d'accéder au coffre de clés avec Get, Unwrap Key et Wrap Key des autorisations. L’exemple de nom de clé est data-protection. La version de la clé ({KEY VERSION} espace réservé) est obtenue à partir de la clé dans le portail Entra ou Azure une fois celle-ci créée.

Exemple :

https://contoso.vault.azure.net/keys/data-protection/{KEY VERSION}

Vous pouvez également configurer l’application pour fournir les valeurs des fichiers de paramètres d’application à l’aide du fournisseur de configuration JSON. Ajoutez les éléments suivants au fichier de paramètres de l’application :

"DistributedTokenCache": {
    "DisableL1Cache": false,
    "L1CacheSizeLimit": 524288000,
    "Encrypt": true,
    "SlidingExpirationInHours": 1
  },
"DataProtection": {
  "BlobUriWithSasToken": "{BLOB URI WITH SAS}",
  "KeyIdentifier": "{KEY IDENTIFIER}"
}

Apportez les modifications suivantes dans le fichier Program :

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    options =>
    {
+       var config = builder.Configuration.GetSection("DistributedTokenCache");

-       options.DisableL1Cache = false;
+       options.DisableL1Cache = config.GetValue<bool>("DisableL1Cache");

-       options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
+       options.L1CacheOptions.SizeLimit = config.GetValue<long>("L1CacheSizeLimit");

-       options.Encrypt = true;
+       options.Encrypt = config.GetValue<bool>("Encrypt");

-       options.SlidingExpiration = TimeSpan.FromHours(1);
+       options.SlidingExpiration = 
+           TimeSpan.FromHours(config.GetValue<int>("SlidingExpirationInHours"));
    });

- builder.Services.AddDataProtection()
-     .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
-     .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), new DefaultAzureCredential());

Ajoutez le code suivant dans lequel les services sont configurés dans le Program fichier :

var config = builder.Configuration.GetSection("DataProtection");

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(
        new Uri(config.GetValue<string>("BlobUriWithSasToken") ??
        throw new Exception("Missing Blob URI")))
    .ProtectKeysWithAzureKeyVault(
        new Uri(config.GetValue<string>("KeyIdentifier") ?? 
        throw new Exception("Missing Key Identifier")), 
        new DefaultAzureCredential());

Pour plus d’informations sur l’utilisation d’un anneau de clés et d’un fournisseur de stockage de clés de protection des données partagés, consultez les ressources suivantes :

Rediriger vers la page d’accueil lors de la déconnexion

Le composant LogInOrOut (Layout/LogInOrOut.razor) définit un champ masqué pour l’URL de retour (ReturnUrl) sur l’URL actuelle (currentURL). Lorsque l’utilisateur se déconnecte de l’application, le fournisseur d’identité renvoie l’utilisateur à la page à partir de laquelle il s’est déconnecté. Si l’utilisateur se déconnecte d’une page sécurisée, il est retourné à la même page sécurisée et renvoyé par le biais du processus d’authentification. Ce flux d’authentification est raisonnable lorsque les utilisateurs doivent modifier régulièrement des comptes.

Vous pouvez également utiliser le composant LogInOrOut suivant, qui ne fournit pas d’URL de retour lors de la déconnexion.

Layout/LogInOrOut.razor :

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span>
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

Sécurité des données météorologiques

Pour plus d’informations sur la façon dont cette application sécurise ses données météorologiques, consultez Sécurisation des données dans Blazor Web Apps avec un rendu automatique interactif.

Résolution des problèmes

Journalisation

L’application serveur est une application standard ASP.NET Core. Consultez les instructions de journalisation ASP.NET Core pour activer un niveau de journalisation inférieur dans l’application serveur.

Pour activer la journalisation de débogage ou de trace pour l'authentification Blazor WebAssembly, consultez la section de la journalisation de l’authentification côté client dans ASP.NET Core Blazor en réglant le sélecteur de version d’article sur ASP.NET Core dans .NET 7 ou version ultérieure.

Erreurs courantes

  • Le débogueur s'interrompt sur une exception lors de la déconnexion avec Microsoft Entra ID Externe

    L'exception suivante arrête le débogueur de Visual Studio lors de la déconnexion avec Microsoft Entra External ID :

    Uncaught TypeError TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence.

    Le débogueur de Visual Studio est interrompu par une exception JavaScript lors de la déconnexion.

    L’exception est levée à partir du code JavaScript Entra. Il ne s’agit donc pas d’un problème avec ASP.NET Core. L’exception n’a pas d’impact sur les fonctionnalités d’application en production. L’exception peut donc être ignorée pendant les tests de développement locaux.

  • Mauvaise configuration de l’application ou du fournisseur d’identité (Identity Provider ou IP)

    Les erreurs les plus courantes sont provoquées par une configuration incorrecte. Voici quelques exemples :

    • Selon les besoins du scénario, une autorité, une instance, un ID de locataire, un domaine de locataire, un ID client ou un URI de redirection manquant ou incorrect empêche une application d’authentifier les clients.
    • Les étendues de requêtes erronées empêchent les clients d’accéder aux points de terminaison d’API web du serveur.
    • Des autorisations d’API serveur incorrectes ou manquantes empêchent les clients d’accéder aux points de terminaison d’API web du serveur.
    • Exécution de l’application sur un autre port que celui configuré dans l’URI de redirection de l'enregistrement de l'application IP. Notez qu’un port n’est pas requis pour Microsoft Entra ID et pour une application s’exécutant à une adresse de test de développement localhost. Cependant, la configuration du port de l’application et le port où l’application s’exécute doivent correspondre pour les adresses non-localhost.

    La couverture de la configuration dans cet article présente des exemples de la configuration correcte. Vérifiez soigneusement la configuration à la recherche d’une application et d’une configuration incorrecte de l’adresse IP.

    Si la configuration semble correcte :

    • Analyser les journaux d’application.

    • Examinez le trafic réseau entre l’application cliente et l'application serveur ou l'adresse IP à l’aide des outils de développement du navigateur. Bien souvent, après qu’une requête a été faite, un message d’erreur précis ou donnant un indice sur la cause du problème est renvoyé au client par le fournisseur d’identité ou l’application serveur. Vous trouverez des conseils d’aide sur les outils de développement dans les articles suivants :

    L’équipe de documentation peut répondre aux commentaires et bogues relatifs aux articles (ouvrez un problème à partir de la section de commentaires de cette page). Toutefois, elle ne peut pas fournir de support produit. Plusieurs forums de support publics sont disponibles pour vous aider à résoudre les problèmes liés à une application. Nous recommandons ce qui suit :

    Les forums précédents ne sont pas détenus ou contrôlés par Microsoft.

    Pour les rapports de bogues de framework reproductibles, non liés à la sécurité, non sensibles et non confidentiels, ouvrez un problème auprès de l’unité de produit ASP.NET Core. N’ouvrez pas de problème auprès de l’unité de produit tant que vous n’avez pas investigué de manière approfondie la cause du problème, sans pouvoir le résoudre par vous-même ou avec l’aide de la communauté sur un forum de support public. L’unité de produit ne peut pas résoudre les problèmes d’applications individuelles qui sont défaillantes en raison d’une mauvaise configuration ou de cas d’usage impliquant des services tiers. Si un rapport est de nature sensible ou confidentielle, ou s’il décrit une faille de sécurité potentielle dans le produit que des attaquants peuvent exploiter, consultez Signaler des problèmes de sécurité et des bugs (référentiel GitHub dotnet/aspnetcore).

  • Client non autorisé pour ME-ID

    Info : Échec de l’autorisation Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]. Ces conditions n’ont pas été remplies : DenyAnonymousAuthorizationRequirement : Nécessite un utilisateur authentifié.

    Erreur de connexion depuis ME-ID :

    • Erreur : unauthorized_client
    • Description : AADB2C90058: The provided application is not configured to allow public clients.

    Pour résoudre l’erreur :

    1. Dans le portail Azure, accédez au manifeste de l’application.
    2. Affectez à l’attribut allowPublicClient la valeur null ou true.

Cookies et données de site

Les cookies et les données de site peuvent persister au fil des mises à jour des applications, et interférer avec les tests et la résolution des problèmes. Effacez ce qui suit quand vous apportez des changements au code d’application, au compte d’utilisateur du fournisseur ou à la configuration de l’application :

  • Cookies de connexion des utilisateurs
  • Cookies d’applications
  • Données de site mises en cache et stockées

Il existe une approche qui permet d’empêcher les cookies et les données de site persistants d’interférer avec les tests et la résolution des problèmes. Elle consiste à :

  • Configurer un navigateur
    • Utilisez un navigateur de test que vous pouvez configurer pour supprimer tous les cookies et toutes les données de site à chaque fois qu’il se ferme.
    • Vérifiez que le navigateur est fermé manuellement ou par l’IDE chaque fois qu’un changement est apporté à la configuration de l’application, de l’utilisateur de test ou du fournisseur.
  • Utilisez une commande personnalisée pour ouvrir un navigateur en mode InPrivate ou Incognito dans Visual Studio :
    • Ouvrez la boîte de dialogue Parcourir avec à partir du bouton Exécuter de Visual Studio.
    • Cliquez sur le bouton Ajouter.
    • Indiquez le chemin de votre navigateur dans le champ Programme. Les chemins d’exécutables suivants sont des emplacements d’installation classiques de Windows 10. Si votre navigateur est installé à un autre emplacement, ou si vous n’utilisez pas Windows 10, indiquez le chemin de l’exécutable du navigateur.
      • Microsoft Edge : C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome : C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox : C:\Program Files\Mozilla Firefox\firefox.exe
    • Dans le champ Arguments, indiquez l’option de ligne de commande utilisée par le navigateur pour qu’il s’ouvre en mode InPrivate ou Incognito. Certains navigateurs nécessitent l’URL de l’application.
      • Microsoft Edge : Utilisez -inprivate.
      • Google Chrome : utilisez --incognito --new-window {URL}, où l’espace réservé {URL} correspond à l’URL à ouvrir (par exemple, https://localhost:5001).
      • Mozilla Firefox : utilisez -private -url {URL}, où l’espace réservé {URL} correspond à l’URL à ouvrir (par exemple https://localhost:5001).
    • Indiquez un nom dans le champ Nom convivial. Par exemple, Firefox Auth Testing
    • Cliquez sur le bouton OK.
    • Pour éviter d’avoir à sélectionner le profil de navigateur pour chaque itération de test avec une application, définissez le profil en tant que profil par défaut avec le bouton Par défaut.
    • Vérifiez que le navigateur est fermé par l’IDE chaque fois qu’un changement est apporté à la configuration de l’application, de l’utilisateur de test ou du fournisseur.

Mises à niveau d’application

Une application fonctionnelle peut échouer immédiatement après la mise à niveau du kit SDK .NET Core sur l’ordinateur de développement ou la modification des versions de package au sein de l’application. Dans certains cas, les packages incohérents peuvent bloquer une application quand vous effectuez des mises à niveau majeures. Vous pouvez résoudre la plupart de ces problèmes en suivant les instructions suivantes :

  1. Effacez les caches de package NuGet du système local en exécutant dotnet nuget locals all --clear à partir d’un interpréteur de commandes.
  2. Supprimez les dossiers bin et obj du projet.
  3. Restaurez et reconstruisez le projet.
  4. Supprimez tous les fichiers du dossier de déploiement sur le serveur avant de redéployer l’application.

Remarque

L’utilisation de versions de package incompatibles avec le framework cible de l’application n’est pas prise en charge. Pour plus d’informations sur un package, utilisez la galerie NuGet.

Démarrer la solution à partir du projet approprié

Blazor Web Apps :

  • Pour l’un des exemples de modèle Backend-for-Frontend (BFF), démarrez la solution à partir du Aspire/Aspire.AppHost projet.
  • Pour l’un des exemples de modèle non BFF, démarrez la solution à partir du projet de serveur.

Blazor Server :

Démarrez la solution à partir du projet serveur.

Inspecter l’utilisateur

Le composant UserClaims suivant peut être utilisé directement dans les applications, ou servir de base à une personnalisation supplémentaire.

UserClaims.razor :

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    [CascadingParameter]
    private Task<AuthenticationState>? AuthState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

Ressources supplémentaires