Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este guia mostra como proteger uma aplicação distribuída .NET Aspire com autenticação e autorização Microsoft Entra ID. Cobre:
-
Interface Blazor Server (
MyService.Web): Login do utilizador com OpenID Connect e aquisição de tokens -
Protected API backend (
MyService.ApiService): validação JWT usando Microsoft. Identity.Web - Fluxo de ponta a ponta: Blazor adquire tokens de acesso e chama a API protegida com a descoberta do serviço Aspire
Este guia assume que começou com um projeto Aspire criado usando o seguinte comando:
aspire new aspire-starter --name MyService
Pré-requisitos
- .NET 9 SDK ou posterior
- .NET Aspire CLI - Veja Instalar Aspire CLI
- Microsoft Entra tenant — Ver Registar aplicações em Microsoft Entra ID para configuração
Sugestão
Novo na Aspire? Veja a visão geral de .NET Aspire.
Compreenda o fluxo de trabalho em duas fases
Este guia segue uma abordagem em duas fases:
| Fase | O que acontece | Result |
|---|---|---|
| Fase 1 | Adicionar código de autenticação com valores provisórios | A aplicação compila mas não executa |
| Fase 2 | Disponibilizar registos de aplicações Microsoft Entra | A aplicação corre com autenticação real |
Registe aplicações no Microsoft Entra ID
Antes de a sua aplicação autenticar utilizadores, precisa de dois registos na Microsoft Entra:
| Registo de Aplicações | Purpose | Configuração das chaves |
|---|---|---|
API (MyService.ApiService) |
Valida tokens recebidos | URI de ID da Aplicação, access_as_user âmbito |
Aplicação Web (MyService.Web) |
Regista utilizadores, adquire tokens | URIs de redirecionamento, segredo do cliente, permissões da API |
Se já tem os registos da aplicação configurados, precisa destes valores para o seu appsettings.json:
- TenantId — O seu ID de inquilino Microsoft Entra
- API ClientId — ID da aplicação (cliente) do registo da sua aplicação API
-
API ID da aplicação URI — Normalmente
api://<api-client-id>(usado emAudienceseScopes) - Web App ClientId — ID da aplicação (cliente) do registo da sua aplicação web
- Segredo do Cliente (ou certificado) — Credencial para a aplicação web (armazenar em segredos do utilizador, não appsettings.json)
-
Escopos — O(s) âmbito(s) que a sua aplicação web solicita, por exemplo,
api://<api-client-id>/.defaultouapi://<api-client-id>/access_as_user
Passo 1: Registar a API
- Vá a centro de administração Microsoft Entra>Identidade>Aplicações>Registros de Apps.
- Selecione Novo registo.
-
Designação:
MyService.ApiService - Tipos de conta suportados: Contas apenas neste diretório organizacional (Inquilino único)
- Selecione Register.
-
Designação:
- Vá a Expor uma API>Adicionar junto ao URI de ID da Aplicação.
- Aceita o padrão (
api://<client-id>) ou personaliza-o. - Selecionar Adicionar um telescópio:
-
Nome do âmbito:
access_as_user - Quem pode consentir: Administradores e utilizadores
- Nome de visualização para consentimento do administrador: Aceder à API MyService
- Descrição do consentimento do administrador: Permite que a aplicação aceda à API MyService em nome do utilizador iniciado sessão.
- Selecione Adicionar escopo.
-
Nome do âmbito:
- Aceita o padrão (
- Copie o ID da Aplicação (cliente) — vai precisar disto para ambos
appsettings.jsonos ficheiros.
Para mais informações, consulte Quickstart: Configurar uma aplicação para expor uma API web.
Passo 2: Registar a aplicação web
- Vá a Registos de aplicações>Novo registo.
-
Designação:
MyService.Web - Tipos de conta suportados: Apenas contas neste diretório organizacional
-
Redirecionar URI: Selecione Web e introduza a URL da sua aplicação +
/signin-oidc- Para desenvolvimento local:
https://localhost:7001/signin-oidc(verifica o porto propriamente ditolaunchSettings.json)
- Para desenvolvimento local:
- Selecione Register.
-
Designação:
- Vá a Autenticação>Adicionar URI para adicionar todos os seus URLs de desenvolvimento (de
launchSettings.json). - Vá para Certificados & segredos>Segredos do cliente>Novo segredo do cliente.
- Adicione uma descrição e um prazo de validade.
- Copie imediatamente o valor secreto — não será mostrado novamente.
- Vá a permissões API>Adicionar uma permissão>Minhas APIs.
- Selecione
MyService.ApiService. - Selecionar
access_as_user>Adicionar permissões. - Selecione Conceder consentimento de administrador para [inquilino] (ou os utilizadores são solicitados na primeira utilização).
- Selecione
- Copie o ID de aplicação (cliente) para a aplicação web
appsettings.json.
Observação
Algumas organizações não permitem segredos de clientes. Para alternativas, veja Credenciais de Certificado ou Autenticação Sem Certificado.
Para mais informações, consulte Quickstart: Registar uma candidatura.
Passo 3: Atualizar configuração
Depois de criar os registos da aplicação, atualize os seus appsettings.json ficheiros:
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"]
}
}
Aplicação 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"]
}
}
Guarde o segredo de forma segura:
cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
| Valor | Onde encontrar |
|---|---|
TenantId |
centro de administração Microsoft Entra > Visão Geral > ID do Inquilino |
API ClientId |
Registos da aplicação > MyService.ApiService > ID da aplicação (cliente) |
Web ClientId |
Registos de aplicações > MyService.Web > ID da aplicação (cliente) |
Client Secret |
Criado no Passo 2 (copiar imediatamente assim que criado) |
Observação
O modelo inicial do Aspire cria automaticamente uma WeatherApiClient classe no MyService.Web projeto. Este HttpClient tipado é utilizado ao longo deste guia para demonstrar como chamar a API protegida. Não precisas de criar esta classe tu próprio — faz parte do modelo.
Comece rapidamente
Esta secção fornece uma referência condensada para adicionar autenticação. Para guias detalhadas, consulte a Parte 1 e a Parte 2.
API (MyService.ApiService)
Instalar o pacote NuGet Microsoft.Identity.Web:
dotnet add package Microsoft.Identity.Web
Adicione a configuração Microsoft Entra a appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id>",
"ClientId": "<api-client-id>",
"Audiences": ["api://<api-client-id>"]
}
}
Registo de autenticação e autorização em Program.cs:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
// ...
app.UseAuthentication();
app.UseAuthorization();
// ...
app.MapGet("/weatherforecast", () => { /* ... */ }).RequireAuthorization();
Aplicação Web (MyService.Web)
Instala o pacote Microsoft.Identity.Web do NuGet:
dotnet add package Microsoft.Identity.Web
Adicione a configuração Microsoft Entra a 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"] }
}
Configure a autenticação, a obtenção de tokens e o cliente de API a jusante em 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();
Adquire e anexa automaticamente tokens, e o MicrosoftIdentityMessageHandler trata de desafios de consentimento e acesso condicional.
Importante
Não te esqueças de criar o UserInfo.razor para o botão de login. Consulte Adicionar componentes da interface do Blazor para mais detalhes.
Observação
BlazorAuthenticationChallengeHandler e LoginLogoutEndpointRouteBuilderExtensions são incluídos no Microsoft.Identity.Web (v3.3.0+). Não é necessário copiar ficheiros.
Identificar ficheiros a modificar
A tabela seguinte lista os ficheiros que altera em cada projeto:
| Projeto | Ficheiro | Changes |
|---|---|---|
| ApiService | Program.cs |
Autenticação JWT Bearer, middleware de autorização |
appsettings.json |
Microsoft Entra configuration | |
.csproj |
Adicionar Microsoft.Identity.Web |
|
| Sítio Web | Program.cs |
Autenticação OIDC, aquisição de tokens, BlazorAuthenticationChallengeHandler |
appsettings.json |
configuração do Microsoft Entra, escopos de API a jusante | |
.csproj |
Adicionar Microsoft.Identity.Web (v3.3.0+) |
|
Components/UserInfo.razor |
Interface do botão de login (novo ficheiro) | |
Components/Layout/MainLayout.razor |
Incluir o componente UserInfo | |
Components/Routes.razor |
AuthorizeRouteView para páginas protegidas | |
| Páginas que chamam APIs | Tentar/apanhar com o ChallengeHandler |
Compreender o fluxo de autenticação
O diagrama seguinte mostra como a interface Blazor, a Microsoft Entra e a API protegida interagem:
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
- O utilizador visita a aplicação Blazor → Não autenticado → vê o botão "Login".
-
O utilizador seleciona Iniciar Sessão → Redireciona para
/authentication/login→ desafio OIDC → Microsoft Entra. -
Utilizador inicia sessão → Microsoft Entra redireciona para
/signin-oidc→ cookie criado. -
O utilizador navega até à página de Meteorologia → Blazor chama
WeatherApiClient.GetAsync(). -
MicrosoftIdentityMessageHandlerinterceta o pedido, adquire um token da cache (ou atualiza silenciosamente) e anexa oAuthorization: Bearer <token>cabeçalho. - API recebe o pedido → Microsoft. O Identity.Web valida o JWT → devolve os dados.
- Blazor renderiza dados meteorológicos.
Rever a estrutura da solução
O modelo inicial do Aspire cria o seguinte layout de projeto:
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
Parte 1: Proteger o backend da API com a Microsoft. Identity.Web
Esta secção configura o projeto API para validar tokens JWT Bearer emitidos pela Microsoft Entra.
Adicione o pacote Microsoft.Identity.Web
Execute o seguinte comando para instalar o pacote NuGet Microsoft.Identity.Web:
cd MyService.ApiService
dotnet add package Microsoft.Identity.Web
Configurar as definições do Microsoft Entra
Adicione a configuração Microsoft Entra a 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": "*"
}
Propriedades principais:
-
ClientId: ID de registo da aplicação API Microsoft Entra -
TenantId: O seu ID de locatário Microsoft Entra, ou"organizations"para multi-locatário, ou"common"para qualquer conta Microsoft -
Audiences: Audiências válidas de tokens (tipicamente o URI do seu ID da Aplicação)
Atualizar API Program.cs
Substitua o conteúdo de MyService.ApiService/Program.cs pelo seguinte código para adicionar autenticação JWT Bearer e proteger os 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);
}
Alterações principais:
- Registar autenticação do portador JWT com
AddMicrosoftIdentityWebApi - Adicionar
app.UseAuthentication()eapp.UseAuthorization()middleware - Aplicar
.RequireAuthorization()em endpoints protegidos
Teste a API protegida
Verifique se a API rejeita pedidos não autenticados e aceita tokens válidos.
Enviar um pedido sem token:
curl https://localhost:<PORT>/weatherforecast
# Expected: 401 Unauthorized
Envie um pedido com um token válido:
curl -H "Authorization: Bearer <TOKEN>" https://localhost:<PORT>/weatherforecast
# Expected: 200 OK with weather data
Parte 2: Configurar a interface Blazor para autenticação
A aplicação Blazor Server usa Microsoft. Identity.Web para:
- Autenticar utilizadores com OIDC
- Adquirir tokens de acesso para chamar a API
- Anexar tokens a pedidos HTTP de saída
Adicione o pacote Microsoft.Identity.Web
Execute o seguinte comando para instalar o pacote NuGet Microsoft.Identity.Web:
cd MyService.Web
dotnet add package Microsoft.Identity.Web
Configurar as definições do Microsoft Entra
Adicione os escopos de configuração do Microsoft Entra e da API a jusante a 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": "*"
}
Detalhes de configuração:
-
ClientId: ID de registo da aplicação web (não o ID da API) -
ClientCredentials: Credenciais para a aplicação web adquirir tokens. Suporta múltiplos tipos de credenciais. Consulte a visão geral das Credenciais para opções prontas para produção. -
Scopes: Deve corresponder ao URI do ID da Aplicação da API com o sufixo/.default
Advertência
Para produção, utilize certificados ou identidade gerida em vez de segredos do cliente. Consulte Autenticação sem certificado para a abordagem recomendada.
Atualizar a aplicação web Program.cs
Substitua o conteúdo de MyService.Web/Program.cs pelo seguinte código para configurar a autenticação OIDC, aquisição de tokens e o cliente API a jusante:
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();
Pontos principais:
-
AddMicrosoftIdentityWebApp: Configura autenticação OIDC -
EnableTokenAcquisitionToCallDownstreamApi: Permite aquisição de tokens para APIs a jusante -
AddScoped<BlazorAuthenticationChallengeHandler>: Trata do consentimento incremental e do acesso condicional no Blazor Server -
AddMicrosoftIdentityMessageHandler: Anexa automaticamente os tokens de autenticação a pedidos HttpClient -
https+http://apiservice: O Aspire Service Discovery resolve isto para a URL real da API -
Ordem do middleware:
UseAuthentication()→UseAuthorization()→ endpoints
A AddMicrosoftIdentityMessageHandler extensão suporta múltiplos padrões de configuração:
Opção 1: Configuração a partir de appsettings.json (mostrada anteriormente)
.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));
Opção 2: Configuração em linha com delegado de ação
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("api://<api-client-id>/.default");
});
Opção 3: Configuração por pedido (sem parâmetros)
.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);
Adicionar componentes da interface do Blazor
Importante
Este passo é frequentemente esquecido. Sem o componente UserInfo, os utilizadores não têm forma de iniciar sessão.
BlazorAuthenticationChallengeHandler e LoginLogoutEndpointRouteBuilderExtensions são incluídos em Microsoft.Identity.Web v3.3.0+. Estão automaticamente disponíveis assim que consultas o pacote — não é necessário copiar ficheiros.
Criar 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>
Adicionar ao layout: Inclua <UserInfo /> no seu 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>
Atualize o Routes.razor para o AuthorizeRouteView
Substituir RouteView por AuthorizeRouteView em 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>
Tratar exceções em páginas que chamam APIs
O Blazor Server requer tratamento explícito de exceções para Acesso Condicional e consentimento. Deve tratar MicrosoftIdentityWebChallengeUserException em todas as páginas que chamam uma API downstream, a menos que a sua aplicação esteja pré-autorizada e solicite todos os scopes antecipadamente em Program.cs.
O exemplo seguinte Weather.razor demonstra o tratamento correto de exceções:
@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}";
}
}
}
}
O padrão funciona da seguinte forma:
-
IsAuthenticatedAsync()verifica se o utilizador está com sessão iniciada antes de fazer chamadas para a API. -
HandleExceptionAsync()capturaMicrosoftIdentityWebChallengeUserException(ou como InnerException). - Caso seja uma exceção de contestação, o utilizador é redirecionado para reautenticar com as declarações ou escopos exigidos.
- Se não for uma exceção de desafio,
HandleExceptionAsyncdevolvefalsepara que possas tratar do erro por ti próprio.
Guardar o segredo do cliente nos segredos do utilizador
Use o .NET Secret Manager para armazenar o segredo do cliente de forma segura durante o desenvolvimento.
Atenção
Nunca armazene segredos no controlo de código fonte.
Inicialize os segredos do utilizador e armazene o segredo do cliente:
cd MyService.Web
dotnet user-secrets init
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "<your-client-secret>"
Depois atualiza appsettings.json para remover o segredo codificado fixamente:
{
"AzureAd": {
"ClientCredentials": [
{
"SourceType": "ClientSecret"
}
]
}
}
Microsoft. O Identity.Web suporta múltiplos tipos de credenciais. Para a utilização em produção, consulte Visão Geral das Credenciais.
Verificar a implementação
Use esta lista de verificação para confirmar que completou todos os passos exigidos.
Projeto API
- [ ] Adicionar
Microsoft.Identity.Webpacote - [ ] Atualizado
appsettings.jsoncom a secçãoAzureAd - [ ] Atualizado
Program.cscomAddMicrosoftIdentityWebApi - [ ] Adicionado
.RequireAuthorization()aos endpoints protegidos
Projeto Web/Blazor
- [ ] Adicionado
Microsoft.Identity.Webpacote (v3.3.0+) - [ ] Atualizado
appsettings.jsoncom as secçõesAzureAdeWeatherApi - [ ] Atualizado
Program.cscom OIDC, obtenção de tokens - [ ] Adicionado
AddScoped<BlazorAuthenticationChallengeHandler>() - [ ] Foi criado
Components/UserInfo.razor(o botão de login) - [ ] Foi atualizado
MainLayout.razorpara incluir<UserInfo /> - [ ] Atualizado
Routes.razorcomAuthorizeRouteView - [ ] Adicionado try/catch com
ChallengeHandlerem cada página que chama APIs - [ ] Guardava o segredo do cliente em segredos de utilizador
Verificação
- [ ]
dotnet buildconsegue - [ ] Registos de aplicações criados no centro de administração do Microsoft Entra
- [ ]
appsettings.jsontem GUIDs reais (sem marcadores de lugar)
Teste e solução de problemas
Depois de concluir a implementação, execute a aplicação e verifique o fluxo de autenticação de ponta a ponta.
Execute o aplicativo
Inicie o Aspire AppHost para lançar tanto os projetos web como API:
# From solution root
dotnet restore
dotnet build
# Launch AppHost (starts both Web and API)
dotnet run --project .\MyService.AppHost\MyService.AppHost.csproj
Teste o fluxo de autenticação
- Abrir o navegador → Blazor Web UI (consulte o painel Aspire para URL).
- Selecione Login → Iniciar sessão com Microsoft Entra.
- Navegar até à página do Tempo .
- Verifique as cargas de dados meteorológicos (a partir da API protegida).
Resolver Problemas Comuns
A tabela seguinte lista problemas frequentes e as suas soluções:
| Issue | Solução |
|---|---|
| 401 em chamadas API | Verifique se os escopos em appsettings.json correspondem ao ID da App URI da API |
| Erro no redirecionamento OIDC | Adicionar /signin-oidc às URIs de redirecionamento da Microsoft Entra |
| Token não anexado | Garantir que AddMicrosoftIdentityMessageHandler seja chamado em HttpClient |
| Falhas na descoberta do serviço | Verifica AppHost.cs referências de ambos os projetos e confirma que estão a funcionar. |
| AADSTS65001 | Consentimento do administrador necessário — conceda consentimento no centro de administração Microsoft Entra |
| Sem botão de login | Certifique-se de que UserInfo.razor exista e esteja incluído em MainLayout.razor |
| Ciclo de consentimento | Garante que o try/catch com HandleExceptionAsync está em todas as páginas de chamada API |
Ativar registo de MSAL
Ao resolver problemas de autenticação, ative o registo detalhado do MSAL para ver os detalhes da aquisição de tokens. Adicione os seguintes níveis logarítmicos a appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Identity": "Debug",
"Microsoft.IdentityModel": "Debug"
}
}
}
Advertência
Desative o registo de depuração em produção porque pode ser muito verboso.
Inspeção dos tokens
Para depurar problemas de tokens, descodifique o seu JWT no jwt.ms e verifique:
-
aud(audiência): Corresponde ao ID do Cliente ou URI do ID da Aplicação da sua API -
iss(emissor): Corresponde ao seu inquilino (https://login.microsoftonline.com/<tenant-id>/v2.0) -
scp(escopos): Contém os escopos necessários -
exp(expiração): O token não expirou
Explore cenários comuns
As secções seguintes mostram como estender a implementação base para casos de uso adicionais.
Proteger as páginas do Blazor
Adicione o [Authorize] atributo às páginas que requerem autenticação:
@page "/weather"
@attribute [Authorize]
Ou definir políticas de autorização em Program.cs:
// Program.cs
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
@attribute [Authorize(Policy = "AdminOnly")]
Validar os escopos na API
Garanta que a API só aceita tokens com escopos específicos, encadeando RequireScope:
app.MapGet("/weatherforecast", () =>
{
// ... implementation
})
.RequireAuthorization()
.RequireScope("access_as_user");
Use tokens de aplicação apenas (serviço para serviço)
Para cenários de daemon ou chamadas service-to-service sem contexto de utilizador, defina RequestAppToken para 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;
});
Use credenciais sem necessidade de certificado para produção
Para implementações em produção no Azure, use identidade gerida em vez de segredos do cliente. Configure a ClientCredentials secção da seguinte forma:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-guid>",
"ClientId": "<web-app-client-id>",
"ClientCredentials": [
{
"SourceType": "SignedAssertionFromManagedIdentity",
"ManagedIdentityClientId": "<user-assigned-mi-client-id>"
}
]
}
}
Para mais informações, consulte Autenticação sem certificado.
Chamar APIs a jusante a partir da API (em nome de)
Se a sua API precisar de chamar outra API a jusante em nome do utilizador, ative a aquisição de tokens em nome deste em 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"));
Adicione a configuração da API a jusante para appsettings.json:
{
"GraphApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": [ "User.Read" ]
}
}
Depois, faça uma chamada à API subsequente a partir de um ponto de extremidade:
{
var user = await downstreamApi.GetForUserAsync<JsonElement>("GraphApi", "me");
return user;
}).RequireAuthorization();
Para mais informações, consulte Chamada de APIs a jusante.