Fügen Sie Microsoft Entra ID-Authentifizierung zu einer .NET Aspire-App hinzu

In diesem Leitfaden wird gezeigt, wie Sie eine .NET Aspire verteilte Anwendung mit Microsoft Entra ID Authentifizierung und Autorisierung sichern. Es umfasst:

  1. Blazor Server frontend (MyService.Web): Benutzeranmeldung mit OpenID Connect und Tokenerwerb
  2. Protected API-Backend (MyService.ApiService): JWT-Überprüfung mit Microsoft.Identity.Web
  3. End-to-End-Flow: Blazor erwirbt Zugriffstoken und ruft die geschützte API mit der Aspire-Dienstermittlung auf.

In diesem Leitfaden wird davon ausgegangen, dass Sie mit einem Aspire-Projekt begonnen haben, das mit dem folgenden Befehl erstellt wurde:

aspire new aspire-starter --name MyService

Voraussetzungen

Tipp

Neu bei Aspire? Siehe .NET Aspire Overview.

Grundlegendes zum zweistufigen Workflow

Dieser Leitfaden folgt einem zweistufigen Ansatz:

Phase Was ist los Ergebnis
Phase 1 Hinzufügen von Authentifizierungscode mit Platzhalterwerten App wird erstellt, aber nicht gestartet
Phase 2 Bereitstellen Microsoft Entra App-Registrierungen App wird mit echter Authentifizierung ausgeführt

Registrieren von Apps in Microsoft Entra ID

Bevor Ihre App Benutzer authentifizieren kann, benötigen Sie zwei App-Registrierungen in Microsoft Entra:

App-Registrierung Purpose Schlüsselkonfiguration
API (MyService.ApiService) Überprüft eingehende Token App-ID-URI, access_as_user Bereich
Web App (MyService.Web) Anmeldung von Benutzern, Erwerb von Tokens Umleitungs-URIs, geheimer Clientschlüssel, API-Berechtigungen

Wenn Sie bereits App-Registrierungen konfiguriert haben, benötigen Sie diese Werte für Folgendes appsettings.json:

  • TenantId – Ihre Microsoft Entra Mandanten-ID
  • API-ClientId – Anwendungs-ID (Client) Ihrer API-App-Registrierung
  • API-App-ID-URI – In der Regel api://<api-client-id> (verwendet in Audiences und Scopes)
  • Web App ClientId – Anwendungs-ID (Client) Ihrer Web-App-Registrierung
  • Clientgeheimnis (oder Zertifikat) – Berechtigungsnachweis für die Webanwendung (in Benutzergeheimnissen speichern, nicht in appsettings.json)
  • Bereiche – Die Bereiche, die Ihre Web-App anfordert, z. B. api://<api-client-id>/.default oder api://<api-client-id>/access_as_user

Schritt 1: Registrieren der API

  1. Wechseln Sie zu Microsoft Entra Admin Center>Identity>Applications>App-Registrierungen.
  2. Wählen Sie Neue Registrierung aus.
    • Name: MyService.ApiService
    • Unterstützte Kontotypen: Nur Konten in diesem Organisationsverzeichnis (einzelner Mandant)
    • Wählen Sie Registrieren aus.
  3. Wechseln Sie zu Expose an API>Hinzufügen neben der Anwendungs-ID-URI.
    • Übernehmen Sie die Standardeinstellung (api://<client-id>) oder passen Sie sie an.
    • Wählen Sie "Bereich hinzufügen" aus:
      • Bereichsname:access_as_user
      • Wer kann zustimmen: Administratoren und Benutzer
      • Anzeigename der Administratorzustimmung: Zugreifen auf myService-API
      • Beschreibung der Administratorzustimmung: Ermöglicht der App den Zugriff auf die MyService-API im Namen des angemeldeten Benutzers.
      • Wählen Sie "Bereich hinzufügen" aus.
  4. Kopieren Sie die Anwendungs-ID (Client-ID). Sie benötigen dies für beide appsettings.json Dateien.

Weitere Informationen finden Sie in der Schnellstartanleitung: Konfigurieren einer App zum Verfügbarmachen einer Web-API.

Schritt 2: Registrieren der Web-App

  1. Wechseln Sie zu App-Registrierungen>Neue Registrierung.
    • Name: MyService.Web
    • Unterstützte Kontotypen: Nur Konten in diesem Organisationsverzeichnis
    • Umleitungs-URI: Wählen Sie "Web" aus, und geben Sie die URL Ihrer App ein+ /signin-oidc
      • Für die lokale Entwicklung: https://localhost:7001/signin-oidc (Überprüfen Sie den launchSettings.json tatsächlichen Port)
    • Wählen Sie Registrieren aus.
  2. Wechseln Sie zu Authentifizierung>URI hinzufügen, um alle Ihre Entwicklungs-URLs (von launchSettings.json) hinzuzufügen.
  3. Wechseln Sie zu Zertifikate und Geheimnisse>Clientgeheimnisse>Neues Clientgeheimnis.
    • Fügen Sie eine Beschreibung und eine Ablauffrist hinzu.
    • Kopieren Sie den geheimen Wert sofort, und es wird nicht mehr angezeigt.
  4. Wechseln Sie zu API-Berechtigungen> "Meine APIs hinzufügen>.
    • Wähle MyService.ApiService aus.
    • Wählen Sie access_as_user>"Berechtigungen hinzufügen" aus.
    • Wählen Sie "Administratorzustimmung für [Mandant] erteilen" (oder Benutzer werden beim ersten Gebrauch aufgefordert).
  5. Kopieren Sie die Anwendungs-ID (Client-ID) für die Web-App.appsettings.json

Hinweis

Einige Organisationen lassen geheime Clientschlüssel nicht zu. Alternativen finden Sie unter Zertifikatanmeldeinformationen oder zertifikatlose Authentifizierung.

Weitere Informationen finden Sie in der Schnellstartanleitung: Registrieren einer Anwendung.

Schritt 3: Aktualisieren der Konfiguration

Aktualisieren Sie nach dem Erstellen der App-Registrierungen Ihre appsettings.json Dateien:

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

Web App (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"]
  }
}

Speichern Sie den geheimen Schlüssel sicher:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Wert Wo finde ich
TenantId Microsoft Entra Admin Center > Übersicht > Mandanten-ID
API ClientId App-Registrierungen > MyService.ApiService > Anwendung (Client)-ID
Web ClientId App-Registrierungen > MyService.Web > Anwendung (Client) ID
Client Secret Erstellt in Schritt 2 (sofort kopieren, wenn erstellt)

Hinweis

Die Aspire-Startvorlage erstellt automatisch eine WeatherApiClient Klasse im MyService.Web Projekt. Dieser typierte HttpClient wird in diesem Handbuch verwendet, um das Aufrufen der geschützten API zu veranschaulichen. Sie müssen diese Klasse nicht selbst erstellen – es ist Teil der Vorlage.


Schneller Einstieg

Dieser Abschnitt enthält einen komprimierten Verweis zum Hinzufügen der Authentifizierung. Ausführliche exemplarische Vorgehensweisen finden Sie in Teil 1 und Teil 2.

API (MyService.ApiService)

Installieren Sie das Microsoft.Identity.Web-NuGet-Paket

dotnet add package Microsoft.Identity.Web

Fügen Sie die Microsoft Entra-Konfiguration zu appsettings.json hinzu:

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

Registriere die Authentifizierung und Autorisierung in Program.cs:

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

Web App (MyService.Web)

Installieren Sie das Microsoft.Identity.Web NuGet-Paket.

dotnet add package Microsoft.Identity.Web

Fügen Sie die Microsoft Entra-Konfiguration zu appsettings.json hinzu:

{
  "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"] }
}

Konfigurieren der Authentifizierung, des Tokenerwerbs und des nachgeschalteten API-Clients in 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();

Der MicrosoftIdentityMessageHandler erwirbt und fügt automatisch Token an, und BlazorAuthenticationChallengeHandler verarbeitet Zustimmungs- und bedingte Zugriff-Herausforderungen.

Von Bedeutung

Vergessen Sie nicht, UserInfo.razor für die Anmeldeschaltfläche zu erstellen. Weitere Informationen finden Sie unter "Blazor UI-Komponenten hinzufügen ".

Hinweis

BlazorAuthenticationChallengeHandler und LoginLogoutEndpointRouteBuilderExtensions sind Bestandteil von Microsoft.Identity.Web (v3.3.0+). Es ist kein Kopieren von Dateien erforderlich.


Identifizieren der zu ändernden Dateien

In der folgenden Tabelle sind die Dateien aufgeführt, die Sie in den einzelnen Projekten ändern:

Project Datei Änderungen
ApiService Program.cs JWT Bearer Authentifizierung, Autorisierungs-Middleware
appsettings.json Microsoft Entra-Konfiguration
.csproj Hinzufügen von Microsoft.Identity.Web
Web Program.cs OIDC-Authentifizierung, Tokenerwerb, BlazorAuthenticationChallengeHandler
appsettings.json Microsoft Entra Konfiguration, nachgeschaltete API-Bereiche
.csproj Hinzufügen von Microsoft.Identity.Web (v3.3.0+)
Components/UserInfo.razor UI des Login-Buttons (neue Datei)
Components/Layout/MainLayout.razor UserInfo-Komponente einschließen
Components/Routes.razor AuthorizeRouteView für geschützte Seiten
Seiten, die APIs aufrufen "Try/Catch mit Challenge-Handler"

Grundlegendes zum Authentifizierungsfluss

Das folgende Diagramm zeigt, wie das Blazor-Frontend, Microsoft Entra und die geschützte API interagieren:

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. Der Benutzer besucht blazor-App → Nicht authentifiziert → sieht die Schaltfläche "Anmelden".
  2. Benutzer wählt "Login" → Leitet zu /authentication/login → OIDC-Herausforderung → Microsoft Entra um.
  3. User meldet sich an → Microsoft Entra leitet weiter zu /signin-oidc → Cookie eingerichtet.
  4. Der Benutzer navigiert zur Wetterseite → Blazor ruft WeatherApiClient.GetAsync() auf.
  5. MicrosoftIdentityMessageHandler fängt die Anforderung ab, erwirbt ein Token aus dem Cache (oder aktualisiert es stillschweigend im Hintergrund) und fügt den Authorization: Bearer <token> Header an.
  6. API empfängt Anforderung → Microsoft.Identity.Web validiert das JWT → gibt Daten zurück.
  7. Blazor rendert Wetterdaten.

Überprüfen der Lösungsstruktur

Die Projektstartvorlage "Aspire" erstellt das folgende Projektlayout:

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

Teil 1: Sichern des API-Back-Ends mit Microsoft. Identity.Web

In diesem Abschnitt wird das API-Projekt so konfiguriert, dass von Microsoft Entra ausgestellte JWT Bearer-Token überprüft werden.

Fügen Sie das Paket Microsoft.Identity.Web hinzu

Führen Sie den folgenden Befehl aus, um das Microsoft.Identity.Web-NuGet-Paket zu installieren:

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

Konfigurieren von Microsoft Entra-Einstellungen

Fügen Sie die Microsoft Entra-Konfiguration zu MyService.ApiService/appsettings.json hinzu:

{
  "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": "*"
}

Wichtige Eigenschaften:

  • ClientId: Microsoft Entra API-App-Registrierungs-ID
  • TenantId: Ihre Microsoft Entra-Mandanten-ID, "organizations" für mehrere Mandanten oder "common" für alle Microsoft-Konten
  • Audiences: Gültige Token-Zielgruppen (in der Regel Ihre App-ID-URI)

API-Program.cs Aktualisieren

Ersetzen Sie den Inhalt von MyService.ApiService/Program.cs durch den folgenden Code, um JWT-Bearer-Authentifizierung hinzuzufügen und Endpunkte zu schützen:

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

Wichtige Änderungen:

  • JWT Bearer-Authentifizierung mit AddMicrosoftIdentityWebApi registrieren
  • Hinzufügen von app.UseAuthentication() und app.UseAuthorization() Middleware
  • Anwenden .RequireAuthorization() auf geschützte Endpunkte

Testen der geschützten API

Überprüfen Sie, ob die API nicht authentifizierte Anforderungen ablehnt und gültige Token akzeptiert.

Senden einer Anforderung ohne Token:

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

Senden einer Anforderung mit einem gültigen Token:

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

Teil 2: Konfigurieren des Blazor-Frontends für die Authentifizierung

Die Blazor Server-App verwendet Microsoft. Identity.Web für:

  • Anmelden von Benutzern mit OIDC
  • Abrufen von Zugriffstoken zum Aufrufen der API
  • Token an ausgehende HTTP-Anforderungen anfügen

Fügen Sie das Paket Microsoft.Identity.Web hinzu

Führen Sie den folgenden Befehl aus, um das Microsoft.Identity.Web-NuGet-Paket zu installieren:

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

Konfigurieren von Microsoft Entra-Einstellungen

Fügen Sie Microsoft Entra Konfigurations- und downstream-API-Bereiche zu MyService.Web/appsettings.json hinzu:

{
  "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": "*"
}

Konfigurationsdetails:

  • ClientId: Web App-Registrierungs-ID (nicht die API-ID)
  • ClientCredentials: Anmeldeinformationen für die Web-App zum Abrufen von Token. Unterstützt mehrere Anmeldeinformationstypen. Unter "Anmeldeinformationen" finden Sie eine Übersicht über produktionsfähige Optionen.
  • Scopes: Muss mit dem App-ID-URI der API mit /.default suffix übereinstimmen

Warnung

Verwenden Sie für die Produktion Zertifikate oder verwaltete Identitäten anstelle von geheimen Clientschlüsseln. Siehe Zertifikatlose Authentifizierung für den empfohlenen Ansatz.

Web-App-Program.cs aktualisieren

Ersetzen Sie den Inhalt von MyService.Web/Program.cs durch den folgenden Code, um die OIDC-Authentifizierung, den Tokenerwerb und den Downstream-API-Client zu konfigurieren:

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

Wichtige Punkte:

  • AddMicrosoftIdentityWebApp: Konfiguriert die OIDC-Authentifizierung
  • EnableTokenAcquisitionToCallDownstreamApi: Aktiviert die Tokenerfassung für nachgeschaltete APIs
  • AddScoped<BlazorAuthenticationChallengeHandler>: Verarbeitet inkrementelle Zustimmung und bedingten Zugriff in Blazor Server
  • AddMicrosoftIdentityMessageHandler: Fügt Bearertoken automatisch an HttpClient-Anforderungen an
  • https+http://apiservice: Aspire Service Discovery löst dies in die tatsächliche API-URL auf.
  • Middleware-Reihenfolge: UseAuthentication()UseAuthorization() → Endpunkte

Die AddMicrosoftIdentityMessageHandler Erweiterung unterstützt mehrere Konfigurationsmuster:

Option 1: Konfiguration von appsettings.json (siehe vorherige Darstellung)

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

Option 2: Inlinekonfiguration mit Aktionsdelegat

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

Option 3: Konfiguration pro Anforderung (parameterlos)

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

Hinzufügen von Blazor-UI-Komponenten

Von Bedeutung

Dieser Schritt wird häufig vergessen. Ohne die UserInfo-Komponente haben Benutzer keine Möglichkeit, sich anzumelden.

BlazorAuthenticationChallengeHandler und LoginLogoutEndpointRouteBuilderExtensions sind in Microsoft.Identity.Web v3.3.0+ verfügbar. Sie sind automatisch verfügbar, sobald Sie auf das Paket verweisen . Es ist kein Dateikopiervorgang erforderlich.

Erstellen: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>

Zum Layout hinzufügen: Fügen Sie <UserInfo /> in Ihr MainLayout.razor ein:

@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>

Aktualisieren von Routes.razor für AuthorizeRouteView

Ersetzen Sie RouteView durch AuthorizeRouteView in 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>

Behandeln von Ausnahmen auf Seiten, die APIs aufrufen

Blazor Server erfordert eine explizite Ausnahmebehandlung für bedingten Zugriff und die Zustimmung. Sie müssen auf jeder Seite, die eine Downstream-API aufruft, MicrosoftIdentityWebChallengeUserException behandeln, es sei denn, Ihre App ist vorautorisiert, und Sie fordern alle Berechtigungen im Voraus in Program.cs an.

Im folgenden Weather.razor Beispiel wird die ordnungsgemäße Ausnahmebehandlung veranschaulicht:

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

Das Muster funktioniert wie folgt:

  1. IsAuthenticatedAsync() überprüft, ob der Benutzer angemeldet ist, bevor API-Aufrufe ausgeführt werden.
  2. HandleExceptionAsync() Catches MicrosoftIdentityWebChallengeUserException (oder als InnerException).
  3. Wenn es sich um eine Herausforderungsausnahme handelt, wird der Benutzer zur erneuten Authentifizierung mit den erforderlichen Ansprüchen oder Scopes umgeleitet.
  4. Wenn es sich nicht um eine Ausnahme bei der Herausforderung handelt, wird HandleExceptionAsync zurückgegeben, false damit Sie den Fehler selbst behandeln können.

Speichern des Client Secret in Benutzergeheimnissen

Verwenden Sie den .NET Geheimen Manager, um den geheimen Clientschlüssel während der Entwicklung sicher zu speichern.

Vorsicht

Übernehmen Sie niemals geheime Schlüssel zur Quellcodeverwaltung.

Initialisieren Sie Benutzergeheimnisse, und speichern Sie den geheimen Clientschlüssel.

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

Aktualisieren Sie appsettings.json dann, um den hartcodierten geheimen Schlüssel zu entfernen:

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

Microsoft. Identity.Web unterstützt mehrere Anmeldeinformationstypen. Informationen zur Produktion finden Sie in der Übersicht zu den Zugangsdaten.


Überprüfen der Implementierung

Verwenden Sie diese Checkliste, um zu bestätigen, dass Sie alle erforderlichen Schritte ausgeführt haben.

API-Projekt

  • [ ] Paket Microsoft.Identity.Web hinzugefügt
  • [ ] Aktualisiert appsettings.json mit Abschnitt AzureAd
  • [ ] Aktualisiert Program.cs mit AddMicrosoftIdentityWebApi
  • [ ] Zu geschützten Endpunkten hinzugefügt .RequireAuthorization()

Web/Blazor-Projekt

  • [ ] Paket Microsoft.Identity.Web hinzugefügt (v3.3.0+)
  • [ ] Aktualisiert appsettings.json mit den Abschnitten AzureAd und WeatherApi
  • [ ] Aktualisiert Program.cs mit OIDC, Token-Erwerb
  • [ ] Hinzugefügt AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Erstellt Components/UserInfo.razor (die Anmeldeschaltfläche)
  • [ ] Aktualisiert MainLayout.razor , um einzuschließen <UserInfo />
  • [ ] Aktualisiert Routes.razor mit AuthorizeRouteView
  • [ ] Try/Catch-Anweisungen mit ChallengeHandler zu jedem Seitenaufruf von APIs hinzugefügt
  • [ ] Gespeichertes Client-Geheimnis in Benutzergeheimnissen

Verifizierung

  • [ ] dotnet build ist erfolgreich
  • [ ] App-Registrierungen im Microsoft Entra Admin Center erstellt
  • [ ] appsettings.json verfügt über echte GUIDs (keine Platzhalter)

Testen und Problembehandlung

Nachdem Sie die Implementierung abgeschlossen haben, führen Sie die Anwendung aus, und überprüfen Sie den End-to-End-Authentifizierungsfluss.

Ausführen der Anwendung

Starten Sie den Aspire AppHost, um sowohl web- als auch API-Projekte zu starten:

# From solution root
dotnet restore
dotnet build

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

Testen des Authentifizierungsflusses

  1. Öffnen Sie browser → Blazor Web UI (überprüfen Sie das Aspire-Dashboard auf URL).
  2. Wählen Sie Login → Melden Sie sich mit Microsoft Entra an.
  3. Navigieren Sie zur Wetterseite .
  4. Überprüfen sie, ob Wetterdaten geladen werden (aus geschützter API).

Allgemeine Probleme beheben

In der folgenden Tabelle sind häufige Probleme und deren Lösungen aufgeführt:

Thema Lösung
401 für API-Aufrufe Überprüfen Sie, ob die Bereiche in appsettings.json mit dem App-ID-URI der API übereinstimmen.
Fehler bei der OIDC-Umleitung Fügen Sie /signin-oidc zu Microsoft Entra Umleitungs-URIs hinzu
Token nicht angehängt Sicherstellen, dass AddMicrosoftIdentityMessageHandler auf HttpClient aufgerufen wird
Service Discovery fehlgeschlagen Überprüfen Sie, ob AppHost.cs sich auf beide Projekte bezieht und diese ausgeführt werden
AADSTS65001 Administratorzustimmung erforderlich – Erteilen der Zustimmung im Microsoft Entra Admin Center
Keine Anmeldeschaltfläche Sicherstellen, dass UserInfo.razor vorhanden ist und in MainLayout.razor enthalten ist
Zustimmungsschleife Stellen Sie sicher, dass try/catch HandleExceptionAsync auf allen API aufrufenden Seiten enthalten ist

Aktivieren der MSAL-Protokollierung

Aktivieren Sie bei Authentifizierungsproblemen die detaillierte MSAL-Protokollierung, um Details zum Tokenerwerb anzuzeigen. Fügen Sie die folgenden Protokollebenen hinzu:appsettings.json

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

Warnung

Deaktivieren Sie die Debugprotokollierung in der Produktion, da sie sehr ausführlich sein kann.

Token prüfen

Um Tokenprobleme zu debuggen, decodieren Sie Ihr JWT bei jwt.ms , und überprüfen Sie Folgendes:

  • aud (audience): Entspricht der Client-ID oder dem App-ID-URI Ihrer API.
  • iss (Aussteller): Entspricht Ihrem Mandanten (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (Bereiche): Enthält die erforderlichen Bereiche.
  • exp (Ablauf): Das Token ist noch nicht abgelaufen.

Erkunden gängiger Szenarien

In den folgenden Abschnitten wird gezeigt, wie Sie die Basisimplementierung für zusätzliche Anwendungsfälle erweitern.

Schützen von Blazor-Seiten

Fügen Sie das [Authorize] Attribut zu Seiten hinzu, die eine Authentifizierung erfordern:

@page "/weather"
@attribute [Authorize]

Oder definieren Sie Autorisierungsrichtlinien in Program.cs:

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

Überprüfen der Gültigkeitsbereiche in der API

Stellen Sie sicher, dass die API nur Token mit bestimmten Bereichen akzeptiert, indem Sie verketten RequireScope:

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

Verwendung von App-only-Token (Dienst-zu-Dienst)

Legen Sie für Daemon-Szenarien oder Dienst-zu-Dienst-Aufrufe ohne Benutzerkontext RequestAppToken auf 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;
});

Verwenden von zertifikatlosen Anmeldeinformationen für die Produktion

Verwenden Sie für Produktionsbereitstellungen in Azure verwaltete Identität anstelle von geheimen Clientschlüsseln. Konfigurieren Sie den ClientCredentials Abschnitt wie folgt:

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

Weitere Informationen finden Sie unter Zertifikatlose Authentifizierung.

Aufruf nachgeschalteter APIs durch die API (im Namen von)

Wenn Ihre API eine andere nachgelagerte API im Auftrag des Benutzers aufrufen muss, aktivieren Sie den Erwerb von Token im Auftrag des Benutzers in 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"));

Fügen Sie die Downstream-API-Konfiguration zu appsettings.json hinzu.

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

Rufen Sie dann die downstream-API von einem Endpunkt auf:

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

Weitere Informationen finden Sie unter Aufrufen von downstream-APIs.