Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Ce guide montre comment sécuriser une application distribuée .NET Aspire avec Microsoft Entra ID pour l’authentification et l’autorisation. Il couvre :
-
Frontend Serveur Blazor (
MyService.Web) : connexion d'utilisateur avec OpenID Connect et acquisition de jetons -
Protéger le serveur principal de l’API (
MyService.ApiService) : validation JWT à l’aide de Microsoft. Identity.Web - Flux de bout en bout : Blazor acquiert des jetons d’accès et appelle l’API protégée avec la découverte de service Aspire.
Ce guide part du principe que vous avez démarré avec un projet Aspire créé à l’aide de la commande suivante :
aspire new aspire-starter --name MyService
Prerequisites
- .NET 9 SDK ou version ultérieure
- .NET Aspire CLI - Voir Install Aspire CLI
- Microsoft Entra tenant — Consultez Créer des applications dans Microsoft Entra ID pour la configuration
Conseil / Astuce
Est-ce la première fois que vous utilisez Aspire ? Consultez .NET Aspire vue d’ensemble.
Comprendre le flux de travail en deux phases
Ce guide suit une approche en deux phases :
| Étape | Que se passe-t-il ? | Résultat |
|---|---|---|
| Phase 1 | Ajouter du code d’authentification avec des valeurs de substitution | Les builds de l'application, mais ne s'exécute pas |
| Phase 2 | Configurer les inscriptions d’applications Microsoft Entra | L’application fonctionne avec une authentification réelle |
Inscrire des applications dans Microsoft Entra ID
Pour que votre application puisse authentifier les utilisateurs, vous avez besoin de deux inscriptions d’application dans Microsoft Entra :
| Enregistrement de l’application | Objectif | Configuration des touches |
|---|---|---|
API (MyService.ApiService) |
Valide les jetons entrants | URI d’ID d’application, access_as_user étendue |
Application web (MyService.Web) |
Connecte des utilisateurs, acquiert des jetons | URI de redirection, secret client, autorisations d’API |
Si vous avez déjà configuré des enregistrements d’applications, vous avez besoin de ces valeurs pour votre appsettings.json:
- TenantId — ID de locataire Microsoft Entra
- API ClientId — ID d’application (client) de votre inscription d’application API
-
URI d’ID d’application API — Généralement
api://<api-client-id>(utilisé dansAudiencesetScopes) - Id client de l'application web — ID d'application (client) de votre enregistrement d'application web
- Clé secrète client (ou certificat) : informations d’identification pour l’application web (stocker dans des secrets utilisateur, et non appsettings.json)
-
Étendues — Les étendues que votre application web demande, par exemple,
api://<api-client-id>/.defaultouapi://<api-client-id>/access_as_user
Étape 1 : Inscrire l’API
- Accédez à centre d’administration Microsoft Entra>Identity>Applications>inscriptions d'applications.
- Sélectionnez Nouvelle inscription.
-
Nom :
MyService.ApiService - Types de comptes pris en charge : Comptes dans cet annuaire organisationnel uniquement (locataire unique)
- Sélectionnez Inscription.
-
Nom :
- Accédez à Exposer une API>Ajouter en regard de l’URI d’ID d’application.
- Acceptez la valeur par défaut (
api://<client-id>) ou personnalisez-la. - Sélectionnez Ajouter une étendue :
-
Nom de l’étendue :
access_as_user - Qui peut donner son consentement : Administrateurs et utilisateurs
- Nom d’affichage du consentement administrateur : Accéder à l’API MyService
- Description du consentement de l’administrateur : Permet à l’application d’accéder à l’API MyService pour le compte de l’utilisateur connecté.
- Sélectionnez Ajouter une étendue.
-
Nom de l’étendue :
- Acceptez la valeur par défaut (
- Copiez l’ID d’application (client) : vous en aurez besoin pour les deux
appsettings.jsonfichiers.
Pour plus d’informations, consultez Démarrage rapide : Configurer une application pour exposer une API web.
Étape 2 : Inscrire l’application web
- Accédez à inscriptions d'applications>New registration.
-
Nom :
MyService.Web - Types de comptes pris en charge : Comptes dans cet annuaire organisationnel uniquement
-
URI de redirection : Sélectionnez Web et entrez l’URL de votre application +
/signin-oidc- Pour le développement local :
https://localhost:7001/signin-oidc(vérifiez votrelaunchSettings.jsonpour le port réel)
- Pour le développement local :
- Sélectionnez Inscription.
-
Nom :
- Accédez à l’authentification>Ajouter un URI pour ajouter toutes vos URL de développement (à partir de
launchSettings.json). - Accédez à Certificats et secrets>Secrets client>Nouveau secret client.
- Ajoutez une description et une expiration.
- Copiez immédiatement la valeur du secret . Elle ne s’affiche pas à nouveau.
- Accédez aux autorisations> d’APIAjouter une autorisation>Mes API.
- Sélectionnez
MyService.ApiService. - Sélectionnez
access_as_user>Ajouter des autorisations. - Sélectionnez Accorder le consentement de l’administrateur pour [locataire] (ou les utilisateurs sont invités à utiliser à la première utilisation).
- Sélectionnez
- Copiez l’ID d’application (client) pour l’application
appsettings.jsonweb.
Note
Certaines organisations n’autorisent pas les secrets client. Pour obtenir des alternatives, consultez Informations d'identification par certificat ou l'Authentification sans certificat.
Pour plus d’informations, consultez Démarrage rapide : Inscrire une application.
Étape 3 : Mettre à jour la configuration
Après avoir créé les enregistrements d’applications, mettez à jour vos appsettings.json fichiers :
API (MyService.ApiService/appsettings.json) :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "YOUR_TENANT_ID",
"ClientId": "YOUR_API_CLIENT_ID",
"Audiences": ["api://YOUR_API_CLIENT_ID"]
}
}
Application web (MyService.Web/appsettings.json) :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "YOUR_TENANT_ID",
"ClientId": "YOUR_WEB_CLIENT_ID",
"CallbackPath": "/signin-oidc",
"ClientCredentials": [
{ "SourceType": "ClientSecret" }
]
},
"WeatherApi": {
"Scopes": ["api://YOUR_API_CLIENT_ID/.default"]
}
}
Stockez le secret de manière sécurisée :
cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
| Valeur | Où trouver |
|---|---|
TenantId |
Centre d'administration Microsoft Entra > Aperçu > ID de locataire |
API ClientId |
Inscriptions d'application > MyService.ApiService > ID d'application (client) |
Web ClientId |
ID d'inscriptions d'applications > MyService.Web > Application (client) |
Client Secret |
Créé à l’étape 2 (copie immédiatement lors de la création) |
Note
Le modèle de démarrage Aspire crée automatiquement une WeatherApiClient classe dans le MyService.Web projet. Ce HttpClient typé est utilisé tout au long de ce guide pour illustrer l’appel de l’API protégée. Vous n’avez pas besoin de créer cette classe vous-même : elle fait partie du modèle.
Prise en main rapide
Cette section fournit une référence condensée pour l’ajout d’authentification. Pour obtenir des procédures pas à pas détaillées, consultez la partie 1 et la partie 2.
API (MyService.ApiService)
Installez le package NuGet Microsoft.Identity.Web :
dotnet add package Microsoft.Identity.Web
Ajoutez la configuration Microsoft Entra à appsettings.json :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id>",
"ClientId": "<api-client-id>",
"Audiences": ["api://<api-client-id>"]
}
}
Inscrivez l’authentification et l’autorisation dans Program.cs:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
// ...
app.UseAuthentication();
app.UseAuthorization();
// ...
app.MapGet("/weatherforecast", () => { /* ... */ }).RequireAuthorization();
Application web (MyService.Web)
Installez le paquet NuGet Microsoft.Identity.Web :
dotnet add package Microsoft.Identity.Web
Ajoutez la configuration Microsoft Entra à appsettings.json :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id>",
"ClientId": "<web-client-id>",
"CallbackPath": "/signin-oidc",
"ClientCredentials": [{ "SourceType": "ClientSecret" }]
},
"WeatherApi": { "Scopes": ["api://<api-client-id>/.default"] }
}
Configurez l’authentification, l’acquisition de jetons et le client d’API en aval dans Program.cs:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<BlazorAuthenticationChallengeHandler>();
builder.Services.AddHttpClient<WeatherApiClient>(client =>
client.BaseAddress = new("https+http://apiservice"))
.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));
// ...
app.UseAuthentication();
app.UseAuthorization();
app.MapGroup("/authentication").MapLoginAndLogout();
Le MicrosoftIdentityMessageHandler acquiert des jetons et les attache automatiquement, et BlazorAuthenticationChallengeHandler gère les défis de consentement et d’accès conditionnel.
Important
N’oubliez pas de créer UserInfo.razor pour le bouton de connexion. Pour plus d’informations, consultez Ajouter des composants d’interface utilisateur Blazor .
Note
BlazorAuthenticationChallengeHandler et LoginLogoutEndpointRouteBuilderExtensions sont disponibles dans Microsoft.Identity.Web (v3.3.0+). Aucune copie de fichier n’est requise.
Identifier les fichiers à modifier
Le tableau suivant répertorie les fichiers que vous modifiez dans chaque projet :
| Projet | Fichier | Modifications |
|---|---|---|
| ApiService | Program.cs |
Authentification JWT Bearer, intergiciel d’autorisation |
appsettings.json |
configuration de Microsoft Entra | |
.csproj |
Ajouter Microsoft.Identity.Web |
|
| Web | Program.cs |
Authentification OIDC, acquisition de jetons, BlazorAuthenticationChallengeHandler |
appsettings.json |
Microsoft Entra configuration, étendues d’API en aval | |
.csproj |
Ajouter Microsoft.Identity.Web (v3.3.0+) |
|
Components/UserInfo.razor |
Interface utilisateur du bouton connexion (nouveau fichier) | |
Components/Layout/MainLayout.razor |
Inclure le composant UserInfo | |
Components/Routes.razor |
AuthorizeRouteView pour les pages protégées | |
| Pages appelant des APIs | Essayer/intercepter avec ChallengeHandler |
Comprendre le flux d’authentification
Le diagramme suivant montre comment le front-end Blazor, Microsoft Entra et l’API protégée interagissent :
flowchart LR
A[User Browser] -->|1 Login OIDC| B[Blazor Server<br/>MyService.Web]
B -->|2 Redirect| C[Microsoft Entra ID]
C -->|3 auth code| B
B -->|4 exchange auth code| C
C -->|5 tokens| B
B -->|6 cookie + session| A
B -->|7 HTTP + Bearer token| D[ASP.NET API<br/>MyService.ApiService<br/>Microsoft.Identity.Web]
D -->|8 Validate JWT| C
D -->|9 Weather data| B
- L’utilisateur visite l’application Blazor → Non authentifié → voit le bouton « Connexion ».
-
Utilisateur sélectionne login → Redirige vers
/authentication/login→ défi OIDC → Microsoft Entra. -
Utilisateur se connecte → Microsoft Entra redirige vers
/signin-oidc→ cookie établi. -
L’utilisateur accède à la page Météo → Blazor appelle
WeatherApiClient.GetAsync(). -
MicrosoftIdentityMessageHandlerintercepte la requête, acquiert un jeton à partir du cache (ou actualise silencieusement) et attache l’en-têteAuthorization: Bearer <token>. - API reçoit la demande → Microsoft. Identity.Web valide le → JWT retourne des données.
- Blazor affiche les données météorologiques.
Passer en revue la structure de la solution
Le modèle de démarrage Aspire crée la disposition de projet suivante :
MyService/
├── MyService.AppHost/ # Aspire orchestration
├── MyService.ApiService/ # Protected API (Microsoft.Identity.Web)
├── MyService.Web/ # Blazor Server (Microsoft.Identity.Web)
├── MyService.ServiceDefaults/ # Shared defaults
└── MyService.Tests/ # Tests
Partie 1 : Sécuriser le back-end d’API avec Microsoft. Identity.Web
Cette section configure le projet d’API pour valider les jetons du porteur JWT émis par Microsoft Entra.
Ajouter le package Microsoft.Identity.Web
Exécutez la commande suivante pour installer le package NuGet Microsoft.Identity.Web :
cd MyService.ApiService
dotnet add package Microsoft.Identity.Web
Configurer les paramètres de Microsoft Entra
Ajoutez la configuration Microsoft Entra à MyService.ApiService/appsettings.json :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<your-tenant-id>",
"ClientId": "<your-api-client-id>",
"Audiences": [
"api://<your-api-client-id>"
]
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Propriétés de clé :
-
ClientId: ID d’inscription d’application API Microsoft Entra -
TenantId: votre ID de locataire Microsoft Entra, ou"organizations"pour un locataire multi-tenant, ou"common"pour n’importe quel compte Microsoft -
Audiences: audiences valides du jeton (généralement l'URI de l'ID de votre application)
Mettre à jour le Program.cs de l’API
Remplacez le contenu de MyService.ApiService/Program.cs par le code suivant pour ajouter l'authentification JWT Bearer et protéger les endpoints :
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// Add Microsoft.Identity.Web JWT Bearer authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseExceptionHandler();
app.UseAuthentication();
app.UseAuthorization();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild",
"Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
app.MapGet("/", () =>
"API service is running. Navigate to /weatherforecast to see sample data.");
app.MapGet("/weatherforecast", () =>
{
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;
})
.WithName("GetWeatherForecast")
.RequireAuthorization();
app.MapDefaultEndpoints();
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Modifications clés :
- Enregistrer l’authentification JWT Bearer avec
AddMicrosoftIdentityWebApi - Ajouter
app.UseAuthentication()etapp.UseAuthorization()intergiciel - Appliquer
.RequireAuthorization()aux points de terminaison protégés
Tester l’API protégée
Vérifiez que l’API rejette les demandes non authentifiées et accepte des jetons valides.
Envoyez une requête sans jeton :
curl https://localhost:<PORT>/weatherforecast
# Expected: 401 Unauthorized
Envoyez une demande avec un jeton valide :
curl -H "Authorization: Bearer <TOKEN>" https://localhost:<PORT>/weatherforecast
# Expected: 200 OK with weather data
Partie 2 : Configurer le front-end Blazor pour l’authentification
L’application Blazor Server utilise Microsoft. Identity.Web à :
- Connecter des utilisateurs avec OIDC
- Acquérir des jetons d’accès pour appeler l’API
- Attacher des jetons aux requêtes HTTP sortantes
Ajouter le package Microsoft.Identity.Web
Exécutez la commande suivante pour installer le package NuGet Microsoft.Identity.Web :
cd MyService.Web
dotnet add package Microsoft.Identity.Web
Configurer les paramètres de Microsoft Entra
Ajoutez la configuration Microsoft Entra et les étendues d’API en aval à MyService.Web/appsettings.json :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<your-tenant>.onmicrosoft.com",
"TenantId": "<tenant-guid>",
"ClientId": "<web-app-client-id>",
"CallbackPath": "/signin-oidc",
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret": "<your-client-secret>"
}
]
},
"WeatherApi": {
"Scopes": [ "api://<api-client-id>/.default" ]
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Détails de la configuration :
-
ClientId: ID d’inscription d’application web (et non l’ID d’API) -
ClientCredentials: Identifiants de l’application web pour acquérir des jetons. Prend en charge plusieurs types d’informations d’identification. Consultez la vue d'ensemble des identifiants pour connaître les options prêtes à l'emploi pour la production. -
Scopes: doit correspondre à l’URI d’ID d’application de l’API avec/.defaultle suffixe
Avertissement
Pour la production, utilisez des certificats ou une identité managée au lieu de secrets clients. Consultez l’authentification sans certificat pour l’approche recommandée.
Mettre à jour la Program.cs de l’application web
Remplacez le contenu de MyService.Web/Program.cs par le code suivant pour configurer l’authentification OIDC, l’acquisition de jetons et le client API en aval :
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using MyService.Web;
using MyService.Web.Components;
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// Authentication + Microsoft Identity Web
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Services.AddCascadingAuthenticationState();
// Blazor components
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
// Blazor authentication challenge handler for incremental consent and Conditional Access
builder.Services.AddScoped<BlazorAuthenticationChallengeHandler>();
builder.Services.AddOutputCache();
// Downstream API client with MicrosoftIdentityMessageHandler
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// Aspire service discovery: resolves "apiservice" at runtime
client.BaseAddress = new("https+http://apiservice");
})
.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.UseOutputCache();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Login/Logout endpoints with incremental consent support
app.MapGroup("/authentication").MapLoginAndLogout();
app.MapDefaultEndpoints();
app.Run();
Points clés :
-
AddMicrosoftIdentityWebApp: configure l’authentification OIDC -
EnableTokenAcquisitionToCallDownstreamApi: active l’acquisition de jetons pour les API en aval -
AddScoped<BlazorAuthenticationChallengeHandler>: gère le consentement incrémentiel et l’accès conditionnel dans Blazor Server -
AddMicrosoftIdentityMessageHandler: attache automatiquement des jetons porteurs aux requêtes HttpClient -
https+http://apiservice: La découverte du service Aspire traduit cela en l'URL réelle de l'API -
Ordre des intergiciels :
UseAuthentication()→UseAuthorization()→ points de terminaison
L’extension AddMicrosoftIdentityMessageHandler prend en charge plusieurs modèles de configuration :
Option 1 : Configuration à partir de appsettings.json (indiqué précédemment)
.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));
Option 2 : Configuration inline avec délégué d’action
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("api://<api-client-id>/.default");
});
Option 3 : Configuration par requête (sans paramètre)
.AddMicrosoftIdentityMessageHandler();
// Then in your service, configure per-request:
var request = new HttpRequestMessage(HttpMethod.Get, "/weatherforecast")
.WithAuthenticationOptions(options =>
{
options.Scopes.Add("api://<api-client-id>/.default");
});
var response = await _httpClient.SendAsync(request);
Ajouter des composants d’interface utilisateur Blazor
Important
Cette étape est fréquemment oubliée. Sans le composant UserInfo, les utilisateurs n’ont aucun moyen de se connecter.
BlazorAuthenticationChallengeHandler et LoginLogoutEndpointRouteBuilderExtensions sont inclus dans Microsoft.Identity.Web v3.3.0+. Elles sont automatiquement disponibles une fois que vous référencez le package : aucune copie de fichier n’est requise.
Créer MyService.Web/Components/UserInfo.razor:
@using Microsoft.AspNetCore.Components.Authorization
<AuthorizeView>
<Authorized>
<span class="nav-item">Hello, @context.User.Identity?.Name</span>
<form action="/authentication/logout" method="post" class="nav-item">
<AntiforgeryToken />
<input type="hidden" name="returnUrl" value="/" />
<button type="submit" class="btn btn-link nav-link">Logout</button>
</form>
</Authorized>
<NotAuthorized>
<a href="/authentication/login?returnUrl=/" class="nav-link">Login</a>
</NotAuthorized>
</AuthorizeView>
Ajouter à la disposition : Inclure <UserInfo /> dans votre MainLayout.razor:
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<UserInfo />
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
Mettre à jour Routes.razor pour AuthorizeRouteView
Remplacez RouteView par AuthorizeRouteView dans Components/Routes.razor :
@using Microsoft.AspNetCore.Components.Authorization
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)">
<NotAuthorized>
<p>You are not authorized to view this page.</p>
<a href="/authentication/login">Login</a>
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>
Gérer les exceptions sur les pages appelant des API
Blazor Server nécessite une gestion explicite des exceptions pour l’accès conditionnel et le consentement. Vous devez gérer MicrosoftIdentityWebChallengeUserException sur chaque page qui appelle une API en aval, sauf si votre application est pré-autorisée et que vous demandez toutes les étendues à l’avance dans Program.cs.
L’exemple suivant Weather.razor illustre la gestion appropriée des exceptions :
@page "/weather"
@attribute [Authorize]
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Identity.Web
@inject WeatherApiClient WeatherApi
@inject BlazorAuthenticationChallengeHandler ChallengeHandler
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-warning">@errorMessage</div>
}
else if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
private string? errorMessage;
protected override async Task OnInitializedAsync()
{
if (!await ChallengeHandler.IsAuthenticatedAsync())
{
await ChallengeHandler.ChallengeUserWithConfiguredScopesAsync("WeatherApi:Scopes");
return;
}
try
{
forecasts = await WeatherApi.GetWeatherAsync();
}
catch (Exception ex)
{
// Handle incremental consent / Conditional Access
if (!await ChallengeHandler.HandleExceptionAsync(ex))
{
errorMessage = $"Error loading weather data: {ex.Message}";
}
}
}
}
Le modèle fonctionne comme suit :
-
IsAuthenticatedAsync()vérifie si l’utilisateur est connecté avant d’effectuer des appels d’API. -
HandleExceptionAsync()intercepteMicrosoftIdentityWebChallengeUserException(ou InnerException). - S’il s’agit d’une exception de défi, l’utilisateur est redirigé pour s’authentifier à nouveau avec les revendications ou étendues requises.
- S’il ne s’agit pas d’une exception de défi,
HandleExceptionAsyncretournefalseafin que vous puissiez gérer l’erreur vous-même.
Stocker le secret client dans les secrets utilisateur
Utilisez le gestionnaire de secrets .NET pour stocker la clé secrète client en toute sécurité pendant le développement.
Avertissement
Ne validez jamais les secrets dans le système de contrôle de version.
Initialisez les secrets des utilisateurs et stockez le secret client.
cd MyService.Web
dotnet user-secrets init
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "<your-client-secret>"
Ensuite, mettez à jour appsettings.json pour supprimer le secret codé en dur :
{
"AzureAd": {
"ClientCredentials": [
{
"SourceType": "ClientSecret"
}
]
}
}
Microsoft. Identity.Web prend en charge plusieurs types d’informations d’identification. Pour la production, consultez Vue d’ensemble des informations d’identification.
Vérifier l’implémentation
Utilisez cette liste de contrôle pour confirmer que vous avez effectué toutes les étapes requises.
Projet d’API
- [ ] Ajout du package
Microsoft.Identity.Web - [ ] Mise à jour
appsettings.jsonavec la sectionAzureAd - [ ] Mis à jour
Program.csavecAddMicrosoftIdentityWebApi - [ ] Ajouté
.RequireAuthorization()aux points de terminaison protégés
Projet Web/Blazor
- [ ] Ajout du package
Microsoft.Identity.Web(v3.3.0+) - [ ] Mise à jour
appsettings.jsonavec les sectionsAzureAdetWeatherApi - [ ] Mis à jour
Program.csavec OIDC, acquisition de jetons - [ ] Ajouté
AddScoped<BlazorAuthenticationChallengeHandler>() - [ ] Créé
Components/UserInfo.razor(bouton de connexion) - [ ] Mise à jour
MainLayout.razorpour inclure<UserInfo /> - [ ] Mis à jour
Routes.razoravecAuthorizeRouteView - [ ] Ajout d'un try/catch avec
ChallengeHandlersur chaque page appelant des API - [ ] Clé secrète client stockée dans les secrets utilisateur
Vérification
- [ ]
dotnet buildréussit - [ ] Créations d'applications dans le centre d'administration Microsoft Entra
- [ ]
appsettings.jsona des GUID réels (pas de texte substitut)
Tester et résoudre les problèmes
Une fois l’implémentation terminée, exécutez l’application et vérifiez le flux d’authentification de bout en bout.
Exécuter l’application
Démarrez Aspire AppHost pour lancer les projets web et API :
# From solution root
dotnet restore
dotnet build
# Launch AppHost (starts both Web and API)
dotnet run --project .\MyService.AppHost\MyService.AppHost.csproj
Tester le flux d’authentification
- Ouvrez le navigateur → interface utilisateur web Blazor (consultez le tableau de bord Aspire pour l’URL).
- Sélectionnez Login → Connectez-vous avec Microsoft Entra.
- Accédez à la page Météo .
- Vérifiez les chargements de données météorologiques (à partir de l’API protégée).
Résoudre les problèmes courants
Le tableau suivant répertorie les problèmes fréquents et leurs solutions :
| Problème | Solution |
|---|---|
| 401 sur les appels d’API | Vérifiez que les étendues en appsettings.json correspondent à l’URI de l’ID d’application de l’API |
| Échec de la redirection OIDC | Ajouter /signin-oidc aux URI de redirection Microsoft Entra |
| Jeton non attaché | Assurez-vous que AddMicrosoftIdentityMessageHandler soit appelée sur le HttpClient |
| Échec de la découverte de service | Vérifiez si les AppHost.cs références des deux projets sont en cours d'exécution. |
| AADSTS65001 | Consentement administrateur requis : accorder le consentement dans le centre d’administration Microsoft Entra |
| Aucun bouton de connexion | Vérifiez UserInfo.razor qu’il existe et qu’il est inclus dans MainLayout.razor |
| Boucle de consentement | Vérifiez que try/catch avec HandleExceptionAsync se trouve sur toutes les pages d’appel d’API |
Activer la journalisation MSAL
Lors de la résolution des problèmes d’authentification, activez la journalisation MSAL détaillée pour afficher les détails de l’acquisition de jetons. Ajoutez les niveaux de log suivants à appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Identity": "Debug",
"Microsoft.IdentityModel": "Debug"
}
}
}
Avertissement
Désactivez la journalisation de débogage en production, car elle peut être très détaillée.
Inspecter les jetons
Pour déboguer les problèmes de jeton, décodez votre JWT à jwt.ms et vérifiez :
-
aud(audience) : correspond à l’ID client ou à l’URI d’ID d’application de votre API -
iss(émetteur) : correspond à votre entité cliente (https://login.microsoftonline.com/<tenant-id>/v2.0) -
scp(étendues) : contient les étendues requises -
exp(expiration) : Le jeton n’a pas expiré
Explorer les scénarios courants
Les sections suivantes montrent comment étendre l’implémentation de base pour des cas d’usage supplémentaires.
Protéger les pages Blazor
Ajoutez l’attribut aux pages qui nécessitent l’authentification [Authorize] :
@page "/weather"
@attribute [Authorize]
Ou définissez des stratégies d’autorisation dans Program.cs:
// Program.cs
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
@attribute [Authorize(Policy = "AdminOnly")]
Valider les périmètres dans l’API
Vérifiez que l’API accepte uniquement les jetons avec des étendues spécifiques en chaînant RequireScope:
app.MapGet("/weatherforecast", () =>
{
// ... implementation
})
.RequireAuthorization()
.RequireScope("access_as_user");
Utiliser des jetons d’application uniquement (service à service)
Pour les scénarios de démon ou les appels de service à service sans contexte utilisateur, définissez RequestAppToken sur true:
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
client.BaseAddress = new("https+http://apiservice");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("api://<api-client-id>/.default");
options.RequestAppToken = true;
});
Utiliser des informations d’identification sans certificat pour la production
Pour les déploiements de production dans Azure, utilisez l’identité managée au lieu des secrets clients. Configurez la ClientCredentials section comme suit :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-guid>",
"ClientId": "<web-app-client-id>",
"ClientCredentials": [
{
"SourceType": "SignedAssertionFromManagedIdentity",
"ManagedIdentityClientId": "<user-assigned-mi-client-id>"
}
]
}
}
Pour plus d’informations, consultez l’authentification sans certificat.
Appeler des API en aval à partir de l’API (on-behalf-of)
Si votre API doit appeler une autre API en aval pour le compte de l’utilisateur, activez l’acquisition de jetons pour le compte dans Program.cs :
// MyService.ApiService/Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Services.AddDownstreamApi("GraphApi", builder.Configuration.GetSection("GraphApi"));
Ajoutez la configuration de l’API en aval à appsettings.json:
{
"GraphApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": [ "User.Read" ]
}
}
Appelez ensuite l’API en aval à partir d’un point de terminaison :
{
var user = await downstreamApi.GetForUserAsync<JsonElement>("GraphApi", "me");
return user;
}).RequireAuthorization();
Pour plus d’informations, consultez Appeler des API en aval.
Contenu connexe
- Démarrage rapide : Connecter des utilisateurs dans une application web
- Démarrage rapide : Protéger une API web
- Appel d’API personnalisées
- Vue d’ensemble des informations d’identification
- Plateforme d’identité Microsoft
- vue d’ensemble .NET Aspire
- Créer votre première application Aspire
- Découverte de services dans .NET Aspire