Přidání ověřování Microsoft Entra ID do aplikace .NET Aspire

Tento průvodce ukazuje, jak zabezpečit distribuovanou aplikaci .NET Aspire pomocí ověřování a autorizace Microsoft Entra ID. Zahrnuje:

  1. Front-end Blazor Serveru (MyService.Web): Přihlášení uživatele pomocí OpenID Connect a získání tokenu
  2. Protected API back-end (MyService.ApiService): Ověřování JWT pomocí Microsoft. Identity.Web
  3. Kompletní tok: Blazor získává přístupové tokeny a volá chráněné rozhraní API pomocí zjišťování služby Aspire.

V této příručce se předpokládá, že jste začali s projektem Aspire vytvořeným pomocí následujícího příkazu:

aspire new aspire-starter --name MyService

Předpoklady

Návod

Začínáte s Aspire? Viz přehled .NET Aspire.

Vysvětlení dvoufázového pracovního postupu

Tento průvodce se řídí dvoufázovým přístupem:

Fáze Co se stane Výsledek
Fáze 1 Přidání ověřovacího kódu se zástupnými hodnotami Aplikace se sestaví, ale nespustí se
Fáze 2 Zřízení registrací aplikací Microsoft Entra Aplikace běží se skutečným ověřováním.

Registrace aplikací v Microsoft Entra ID

Než bude vaše aplikace moct ověřovat uživatele, budete potřebovat dvě registrace aplikací v Microsoft Entra:

Registrace aplikace Purpose Konfigurace klíče
API (MyService.ApiService) Ověřuje příchozí tokeny. URI ID aplikace, access_as_user obor
Webová aplikace (MyService.Web) Přihlášení uživatelů, získání tokenů URI přesměrování, tajný klíč klienta, oprávnění API

Pokud už máte nakonfigurované registrace aplikací, potřebujete pro svoji appsettings.jsonaplikaci tyto hodnoty:

  • TenantId – ID vašeho tenanta Microsoft Entra
  • API ClientId – ID aplikace (klienta) registrace vaší aplikace API
  • Identifikátor URI ID aplikace API – obvykle api://<api-client-id> (používá se v Audiences a Scopes)
  • ID klienta webové aplikace – ID aplikace (klienta) registrace webové aplikace
  • Tajný klíč klienta (nebo certifikát) – přihlašovací údaje pro webovou aplikaci (ukládání do tajných kódů uživatelů, nikoli appsettings.json)
  • Scopes – Rozsahy oprávnění, které vaše webová aplikace vyžaduje, například api://<api-client-id>/.default nebo api://<api-client-id>/access_as_user

Krok 1: Registrace rozhraní API

  1. Přejděte na Centrum pro správu Microsoft Entra>Identity>Applications>Registrace aplikací.
  2. Vyberte Nová registrace.
    • Jméno:MyService.ApiService
    • Podporované typy účtů: Účty pouze v tomto organizačním adresáři (jeden tenant)
    • Vyberte Zaregistrovat.
  3. Přejděte na Zveřejnit rozhraní API>Přidat vedle identifikátoru URI ID aplikace.
    • Přijměte výchozí (api://<client-id>) nebo ho přizpůsobte.
    • Vyberte Přidat obor:
      • Název oboru:access_as_user
      • Kdo může souhlasit: Správci a uživatelé
      • Zobrazovaný název souhlasu správce: Přístup k rozhraní MyService API
      • Popis souhlasu správce: Umožňuje aplikaci přístup k rozhraní MYService API jménem přihlášeného uživatele.
      • Vyberte Přidat rozsah.
  4. Zkopírujte ID aplikace (klienta) – budete ho potřebovat pro oba appsettings.json soubory.

Další informace najdete v tématu Rychlý start: Konfigurace aplikace pro zveřejnění webového rozhraní API.

Krok 2: Registrace webové aplikace

  1. Přejděte na Registrace aplikací>Nová registrace.
    • Jméno:MyService.Web
    • Podporované typy účtů: Účty pouze v tomto organizačním adresáři
    • Identifikátor URI přesměrování: Vyberte Web a zadejte adresu URL aplikace + /signin-oidc
      • Pro místní vývoj: https://localhost:7001/signin-oidc (zkontrolujte svůj launchSettings.json pro skutečný port)
    • Vyberte Zaregistrovat.
  2. Přejděte na Ověřování>Přidat URI a přidejte všechny své vývojové adresy URL (z launchSettings.json).
  3. Přejděte na Certifikáty a tajné>kódy> klientaNové tajné klíče klienta.
    • Přidejte popis a vypršení platnosti.
    • Zkopírujte hodnotu tajného kódu okamžitě – znovu se nezobrazí.
  4. Přejděte na oprávnění >– Přidejte oprávnění>Moje rozhraní API.
    • Vyberte možnost MyService.ApiService.
    • Vyberte access_as_user>Přidat oprávnění.
    • Vyberte Udělit souhlas správce pro [tenanta] (nebo se uživatelům zobrazí výzva k prvnímu použití).
  5. Zkopírujte ID aplikace (klienta) pro webovou aplikaci appsettings.json.

Poznámka:

Některé organizace nepovolují tajné kódy klientů. Alternativy najdete v tématu Přihlašovací údaje certifikátu nebo ověřování bez certifikátů.

Další informace najdete v tématu Rychlý start: Registrace aplikace.

Krok 3: Aktualizace konfigurace

Po vytvoření registrací aplikací aktualizujte soubory appsettings.json :

Rozhraní 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"]
  }
}

Webová aplikace (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"]
  }
}

Bezpečně uložte tajný kód:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Hodnota Kde najít
TenantId Microsoft Entra Administrační centrum > – Přehled > ID tenanta
API ClientId Registrace aplikací > MyService.ApiService > ID aplikace (klienta)
Web ClientId Registrace aplikací > MyService.Web > ID aplikace (klienta)
Client Secret Vytvořeno v kroku 2 (kopírování okamžitě po vytvoření)

Poznámka:

Úvodní šablona Aspire automaticky vytvoří WeatherApiClient třídu v MyService.Web projektu. Tento typ HttpClient se používá v tomto průvodci k předvedení volání chráněného rozhraní API. Tuto třídu nemusíte vytvářet sami – je součástí šablony.


Začněte rychle

Tato část poskytuje zhuštěný přehled pro přidání autentizace. Podrobné návody najdete v části 1 a 2.

ROZHRANÍ API (MyService.ApiService)

Nainstalujte balíček NuGet Microsoft.Identity.Web:

dotnet add package Microsoft.Identity.Web

Přidejte konfiguraci Microsoft Entra do appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<tenant-id>",
    "ClientId": "<api-client-id>",
    "Audiences": ["api://<api-client-id>"]
  }
}

Registrujte ověřování a autorizaci v Program.cs:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
// ...
app.UseAuthentication();
app.UseAuthorization();
// ...
app.MapGet("/weatherforecast", () => { /* ... */ }).RequireAuthorization();

Webová aplikace (MyService.Web)

Nainstalujte balíček NuGet Microsoft.Identity.Web.

dotnet add package Microsoft.Identity.Web

Přidejte konfiguraci Microsoft Entra do 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"] }
}

Konfigurace ověřování, získání tokenu a podběžného klienta rozhraní API v 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();

Automaticky MicrosoftIdentityMessageHandler získá a připojí tokeny a BlazorAuthenticationChallengeHandler zpracuje problémy se souhlasem a podmíněným přístupem.

Důležité

Nezapomeňte vytvořit UserInfo.razor tlačítko pro přihlášení. Podrobnosti najdete v tématu Přidání komponent uživatelského rozhraní Blazor .

Poznámka:

BlazorAuthenticationChallengeHandler a LoginLogoutEndpointRouteBuilderExtensions jsou dodávány v Microsoft.Identity.Web (v3.3.0+). Není vyžadováno kopírování souborů.


Identifikace souborů k úpravě

Následující tabulka uvádí soubory, které změníte v jednotlivých projektech:

Projekt Soubor Changes
ApiService Program.cs JWT Bearer auth, autorizační middleware
appsettings.json konfigurace Microsoft Entra
.csproj Přidejte Microsoft.Identity.Web
Web Program.cs Ověřování OIDC, získání tokenu, BlazorAuthenticationChallengeHandler
appsettings.json konfigurace Microsoft Entra, rozsahy podřízených rozhraní API
.csproj Přidejte Microsoft.Identity.Web (v3.3.0+)
Components/UserInfo.razor Uživatelské rozhraní přihlašovacího tlačítka (nový soubor)
Components/Layout/MainLayout.razor Zahrnout součást UserInfo
Components/Routes.razor AuthorizeRouteView pro chráněné stránky
Stránky volající rozhraní API Vyzkoušení nebo zachycení pomocí challengehandleru

Vysvětlení toku ověřování

Následující diagram znázorňuje interakci front-endu Blazoru, Microsoft Entra a chráněného rozhraní API:

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
  1. Uživatel navštíví aplikaci Blazor → Neověřené → zobrazí tlačítko Přihlásit se.
  2. Uživatel vybere přihlášení → Přesměrování na /authentication/login → výzva OIDC → Microsoft Entra.
  3. Uživatel se přihlásí → Microsoft Entra přesměruje na /signin-oidc → soubor cookie vytvořený.
  4. Uživatel přejde na stránku Počasí → volání WeatherApiClient.GetAsync()Blazoru .
  5. MicrosoftIdentityMessageHandler zachytí požadavek, získá token z mezipaměti (nebo tiše obnoví) a připojí hlavičku Authorization: Bearer <token>.
  6. API obdrží požadavek → Microsoft.Identity.Web ověřuje JWT → vrací data.
  7. Blazor vykreslí data o počasí.

Kontrola struktury řešení

Úvodní šablona Aspire vytvoří následující rozložení projektu:

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

Část 1: Zabezpečení back-endu rozhraní API pomocí Microsoft Identity.Web

Tato část nakonfiguruje projekt rozhraní API tak, aby ověřil tokeny JWT Bearer vydané Microsoft Entra.

Přidejte balíček Microsoft.Identity.Web

Spusťte následující příkaz pro instalaci balíčku NuGet Microsoft.Identity.Web:

cd MyService.ApiService
dotnet add package Microsoft.Identity.Web

Konfigurace nastavení Microsoft Entra

Přidejte konfiguraci Microsoft Entra do 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": "*"
}

Vlastnosti klíče:

  • ClientId: ID registrace aplikace API Microsoft Entra
  • TenantId: ID tenanta Microsoft Entra nebo "organizations" pro více tenantů nebo "common" pro libovolný Microsoft účet
  • Audiences: Platné cílové skupiny tokenů (obvykle identifikátor URI ID vaší aplikace)

Aktualizace rozhraní API v Program.cs

Nahraďte obsah MyService.ApiService/Program.cs následujícím kódem pro přidání ověřování pomocí nosiče JWT a ochrany koncových bodů.

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);
}

Klíčové změny:

  • Registrace autentizace typu JWT Bearer pomocí AddMicrosoftIdentityWebApi
  • Přidejte app.UseAuthentication() a app.UseAuthorization() middleware
  • Použít .RequireAuthorization() na chráněné koncové body

Testování chráněného rozhraní API

Ověřte, že rozhraní API odmítne neověřené požadavky a přijímá platné tokeny.

Odeslání požadavku bez tokenu:

curl https://localhost:<PORT>/weatherforecast
# Expected: 401 Unauthorized

Odeslání požadavku s platným tokenem:

curl -H "Authorization: Bearer <TOKEN>" https://localhost:<PORT>/weatherforecast
# Expected: 200 OK with weather data

Část 2: Konfigurace front-endu Blazor pro ověřování

Aplikace Blazor Server používá Microsoft. Identity.Web do:

  • Přihlášení uživatelů pomocí OIDC
  • Získání přístupových tokenů pro volání rozhraní API
  • Připojení tokenů k odchozím požadavkům HTTP

Přidejte balíček Microsoft.Identity.Web

Spuštěním následujícího příkazu nainstalujte balíček NuGet Microsoft.Identity.Web:

cd MyService.Web
dotnet add package Microsoft.Identity.Web

Konfigurace nastavení Microsoft Entra

Přidejte rozsahy konfigurace Microsoft Entra a podřízeného rozhraní API do 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": "*"
}

Podrobnosti o konfiguraci:

  • ClientId: ID registrace webové aplikace (ne ID rozhraní API)
  • ClientCredentials: Přihlašovací údaje pro webovou aplikaci k získání tokenů. Podporuje více typů přihlašovacích údajů. Viz Přehled přihlašovacích údajů pro možnosti připravené pro produkční prostředí.
  • Scopes: Musí odpovídat URI ID aplikace rozhraní API s /.default příponou.

Výstraha

V produkčním prostředí místo tajných klíčů klienta používejte certifikáty nebo spravovanou identitu. Doporučený přístup najdete v tématu Ověřování bez certifikátů .

Aktualizace Program.cs webové aplikace

Nahraďte obsah MyService.Web/Program.cs následujícím kódem pro konfiguraci ověřování OIDC, získání tokenu a podřízeného klienta rozhraní API:

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();

klíčové body:

  • AddMicrosoftIdentityWebApp: Konfiguruje ověřování OIDC.
  • EnableTokenAcquisitionToCallDownstreamApi: Povolí získání tokenu pro podřízená rozhraní API.
  • AddScoped<BlazorAuthenticationChallengeHandler>: Zpracovává přírůstkový souhlas a podmíněný přístup na Blazor Serveru.
  • AddMicrosoftIdentityMessageHandler: Automaticky připojí nosné tokeny k žádostem HttpClient.
  • https+http://apiservice: Zjišťování služby Aspire převede tuto hodnotu na skutečnou adresu URL rozhraní API.
  • Pořadí middlewaru: UseAuthentication()UseAuthorization() → koncové body

Rozšíření AddMicrosoftIdentityMessageHandler podporuje více vzorů konfigurace:

Možnost 1: Konfigurace z appsettings.json (viz předchozí)

.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));

Možnost 2: Inline konfigurace s delegátem Action

.AddMicrosoftIdentityMessageHandler(options =>
{
    options.Scopes.Add("api://<api-client-id>/.default");
});

Možnost 3: Konfigurace podle požadavku (bez parametrů)

.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);

Přidání komponent uživatelského rozhraní Blazor

Důležité

Tento krok je často zapomenutý. Bez komponenty UserInfo nemají uživatelé způsob, jak se přihlásit.

BlazorAuthenticationChallengeHandler a LoginLogoutEndpointRouteBuilderExtensions jsou dodávány v Microsoft.Identity.Web v3.3.0+ Jakmile na balíček odkazujete, jsou automaticky dostupné – nevyžaduje se kopírování souborů.

Vytvořit 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>

Přidat do rozložení: Zahrnout <UserInfo /> do svého 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>

Aktualizace Routes.razor pro AuthorizeRouteView

Nahradit RouteView za AuthorizeRouteView v 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>

Zpracování výjimek na stránkách volajících rozhraní API

Blazor Server vyžaduje explicitní zpracování výjimek pro podmíněný přístup a souhlas. Každou stránku, která volá podřízené rozhraní API, musíte zpracovat pomocí MicrosoftIdentityWebChallengeUserException, pokud vaše aplikace není předem autorizována, a vyžádáte si všechny scopy předem v Program.cs.

Následující Weather.razor příklad ukazuje správné zpracování výjimek:

@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}";
            }
        }
    }
}

Vzor funguje takto:

  1. IsAuthenticatedAsync() zkontroluje, jestli je uživatel přihlášený před voláním rozhraní API.
  2. HandleExceptionAsync() zachytí MicrosoftIdentityWebChallengeUserException (nebo jako InnerException).
  3. Pokud se jedná o výjimku výzvy, uživatel se přesměruje na opětovné ověření pomocí požadovaných deklarací identity nebo oborů.
  4. Pokud se nejedná o výjimku výzvy, HandleExceptionAsync vrátí false, abyste mohli chybu zpracovat sami.

Uložení klientského tajemství do uživatelských tajemství

Pomocí .NET Secret Manageru bezpečně uložte tajný klíč klienta během vývoje.

Upozornění

Nikdy neukládejte tajné informace do správy zdrojového kódu.

Inicializace tajných kódů uživatelů a uložení tajného klíče klienta:

cd MyService.Web
dotnet user-secrets init
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "<your-client-secret>"

Potom aktualizujte appsettings.json a odeberte pevně zakódovaný tajný klíč:

{
  "AzureAd": {
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret"
      }
    ]
  }
}

Microsoft. Identity.Web podporuje více typů přihlašovacích údajů. V produkčním prostředí se podívejte na přehled přihlašovacích údajů.


Ověření implementace

Pomocí tohoto kontrolního seznamu potvrďte, že jste dokončili všechny požadované kroky.

Projekt rozhraní API

  • [ ] Přidání balíčku Microsoft.Identity.Web
  • [ ] Aktualizováno appsettings.json přidáním oddílu AzureAd
  • [ ] Aktualizováno Program.cs pomocí AddMicrosoftIdentityWebApi
  • [ ] Přidáno .RequireAuthorization() do chráněných koncových bodů

Projekt Web/Blazor

  • [ ] Přidání balíčku Microsoft.Identity.Web (v3.3.0+)
  • [ ] Aktualizováno appsettings.json o oddíly AzureAd a WeatherApi
  • [ ] Aktualizováno Program.cs s využitím OIDC, získávání tokenů
  • [ ] Přidáno AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Vytvořeno Components/UserInfo.razor (tlačítko pro přihlášení)
  • [ ] Aktualizováno MainLayout.razor tak, aby zahrnovalo <UserInfo />
  • [ ] Aktualizováno Routes.razor pomocí AuthorizeRouteView
  • [ ] Přidáno try/catch s ChallengeHandler na každou stránku volající rozhraní API
  • [ ] Uložený tajný klíč klienta v uživatelských tajných klíčích

Ověření

  • [ ] dotnet build uspěje
  • [ ] Registrace aplikací vytvořené v Microsoft Entra centru pro správu
  • [ ] appsettings.json má skutečné identifikátory GUID (žádné zástupné symboly)

Test a řešení potíží

Po dokončení implementace spusťte aplikaci a ověřte tok kompletního ověřování.

Spuštění aplikace

Spusťte Aspire AppHost a spusťte jak webové projekty, tak projekty rozhraní API:

# From solution root
dotnet restore
dotnet build

# Launch AppHost (starts both Web and API)
dotnet run --project .\MyService.AppHost\MyService.AppHost.csproj

Otestování toku ověřování

  1. Otevřete prohlížeč → webové uživatelské rozhraní Blazor (zkontrolujte řídicí panel dashboard Aspire pro adresu URL).
  2. Vyberte Login → Přihlásit se pomocí Microsoft Entra.
  3. Přejděte na stránku Počasí .
  4. Ověřte načtení dat o počasí (z chráněného rozhraní API).

Řešení běžných problémů

Následující tabulka uvádí časté problémy a jejich řešení:

Problém Řešení
401 při voláních rozhraní API Ověřte, že obory ve appsettings.json odpovídají identifikátoru URI ID aplikace rozhraní API.
Selhání přesměrování OIDC Přidejte /signin-oidc k identifikátorům URI přesměrování Microsoft Entra
Token není připojený Ujistěte se, že je AddMicrosoftIdentityMessageHandler voláno na HttpClient
Neuspělo zjišťování služeb Zkontrolujte odkazy na oba projekty, které jsou spuštěny
AADSTS65001 Požadován souhlas správce – udělení souhlasu v Centrum pro správu Microsoft Entra
Bez přihlašovacího tlačítka Ujistěte se, že UserInfo.razor existuje a je součástí MainLayout.razor
Smyčka souhlasu Ujistěte se, že try/catch with HandleExceptionAsync je přítomno na všech stránkách volajících API.

Povolte protokolování MSAL

Při řešení potíží s ověřováním povolte podrobné protokolování MSAL a zobrazte podrobnosti o získání tokenu. Přidejte následující úrovně protokolu:appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Identity": "Debug",
      "Microsoft.IdentityModel": "Debug"
    }
  }
}

Výstraha

Zakažte protokolování ladění v produkčním prostředí, protože může být velmi podrobné.

Kontrola tokenů

Pokud chcete ladit problémy s tokeny, dekódujte JWT na jwt.ms a ověřte:

  • aud (cílová skupina): Odpovídá ID klienta rozhraní API nebo identifikátoru URI ID aplikace.
  • iss (vystavitel): Odpovídá vašemu tenantovi (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (obory):: Obsahuje požadované obory.
  • exp (vypršení platnosti): Platnost tokenu nevypršela

Prozkoumání běžných scénářů

Následující části ukazují, jak rozšířit základní implementaci pro další případy použití.

Ochrana stránek Blazor

[Authorize] Přidejte atribut na stránky, které vyžadují ověření:

@page "/weather"
@attribute [Authorize]

Nebo definujte zásady autorizace v Program.cs:

// Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
@attribute [Authorize(Policy = "AdminOnly")]

Ověření oborů v rozhraní API

Ujistěte se, že rozhraní API přijímá pouze tokeny s konkrétními oprávněními řetězením RequireScope:

app.MapGet("/weatherforecast", () =>
{
    // ... implementation
})
.RequireAuthorization()
.RequireScope("access_as_user");

Použití tokenů pouze pro aplikace (service-to-service)

V případě scénářů démona nebo volání mezi službami bez kontextu uživatele nastavte RequestAppToken na 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;
});

Použití přihlašovacích údajů bez certifikátů pro produkční prostředí

Pro produkční nasazení v Azure použijte spravovanou identitu místo tajných klíčů klienta. ClientCredentials Nakonfigurujte oddíl následujícím způsobem:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<tenant-guid>",
    "ClientId":  "<web-app-client-id>",
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity",
        "ManagedIdentityClientId": "<user-assigned-mi-client-id>"
      }
    ]
  }
}

Další informace najdete v tématu Ověřování bez certifikátů.

Volání podřízených API z API (on-behalf-of)

Pokud vaše rozhraní API potřebuje za uživatele volat jiné podřízené rozhraní API, povolte získání tokenu jménem uživatele v 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"));

Přidejte konfiguraci podřízeného rozhraní API do appsettings.json:

{
  "GraphApi": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": [ "User.Read" ]
  }
}

Potom volejte podřízené rozhraní API z koncového bodu:

{
    var user = await downstreamApi.GetForUserAsync<JsonElement>("GraphApi", "me");
    return user;
}).RequireAuthorization();

Další informace naleznete v sekci Volání podřízených rozhraní API.