Microsoft Entra ID-verificatie toevoegen aan een .NET Aspire-app

Deze handleiding laat zien hoe u een gedistribueerde .NET Aspire gedistribueerde toepassing beveiligt met Microsoft Entra ID verificatie en autorisatie. Hierin wordt het volgende behandeld:

  1. Blazor Server-front-end (MyService.Web): Gebruikersaanmelding met OpenID Connect en tokenverwerving
  2. Protected API backend (MyService.ApiService): JWT-validatie met behulp van Microsoft. Identity.Web
  3. End-to-end flow: Blazor verkrijgt toegangstokens en roept de beveiligde API aan met Aspire-serviceontdekking

In deze handleiding wordt ervan uitgegaan dat u bent begonnen met een Aspire-project dat is gemaakt met behulp van de volgende opdracht:

aspire new aspire-starter --name MyService

Vereiste voorwaarden

Aanbeveling

Nieuw bij Aspire? Zie .NET Aspire overzicht.

Inzicht in de werkstroom in twee fasen

Deze handleiding volgt een tweefase-benadering:

Fase Wat gebeurt er? Resultaat
Fase 1 Verificatiecode toevoegen met placeholderwaarden De app bouwt maar werkt niet.
Fase 2 De app-registraties van Microsoft Entra inrichten App wordt uitgevoerd met echte authenticatie

Apps registreren in Microsoft Entra ID

Voordat uw app gebruikers kan verifiëren, hebt u twee app-registraties nodig in Microsoft Entra:

App-registratie Purpose Sleutelconfiguratie
API (MyService.ApiService) Hiermee worden binnenkomende tokens gevalideerd App-id-URI, access_as_user bereik
Web-app (MyService.Web) Gebruikers aanmelden, tokens verkrijgen Omleidings-URI's, clientgeheim, API-machtigingen

Als u app-registraties al hebt geconfigureerd, hebt u deze waarden nodig voor het appsettings.jsonvolgende:

  • TenantId — de tenant-id van uw Microsoft Entra
  • API ClientId — Toepassings-id (client) van uw API-app-registratie
  • API-app-id-URI : meestal api://<api-client-id> (gebruikt in Audiences en Scopes)
  • Web App ClientId — Toepassings-id (client) van uw web-app-registratie
  • Clientgeheim (of certificaat): referentie van de webapp (opslaan in user-secrets, niet in appsettings.json)
  • Machtigingen: de machtigingen die uw web-app aanvraagt, bijvoorbeeld api://<api-client-id>/.default of api://<api-client-id>/access_as_user

Stap 1: de API registreren

  1. Ga naar Microsoft Entra-beheercentrum>Identity>Applications>App-registraties.
  2. Selecteer Nieuwe registratie.
    • Naam:MyService.ApiService
    • Ondersteunde accounttypen: Alleen accounts in deze organisatiemap (Single-tenant)
    • Selecteer Registreren.
  3. Ga naar Blootstellen van een API>Toevoegen naast de toepassings-ID URI.
    • Accepteer de standaardwaarde (api://<client-id>) of pas deze aan.
    • Selecteer Een bereik toevoegen:
      • Bereiknaam:access_as_user
      • Wie kan toestemming geven: Beheerders en gebruikers
      • Weergavenaam van beheerderstoestemming: Toegang tot MyService-API
      • Beschrijving van beheerderstoestemming: Hiermee kan de app namens de aangemelde gebruiker toegang krijgen tot de MyService-API.
      • Selecteer Voeg bereik toe.
  4. Kopieer de toepassings-id (client): u hebt deze nodig voor beide appsettings.json bestanden.

Zie quickstart: Een app configureren om een web-API beschikbaar te maken voor meer informatie.

Stap 2: de web-app registreren

  1. Ga naar App-registraties>Nieuwe registratie.
    • Naam:MyService.Web
    • Ondersteunde accounttypen: Alleen accounts in deze organisatiemap
    • Omleidings-URI: Selecteer Web en voer de URL van uw app in + /signin-oidc
      • Voor lokale ontwikkeling: https://localhost:7001/signin-oidc (controleer uw launchSettings.json op de werkelijke poort)
    • Selecteer Registreren.
  2. Ga naar Verificatie>toevoegen URI om al uw ontwikkelings-URL's (van launchSettings.json) toe te voegen.
  3. Ga naar Certificaten en geheimen>Clientgeheimen>Nieuw clientgeheim.
    • Voeg een beschrijving en vervaldatum toe.
    • Kopieer de geheime waarde onmiddellijk. Deze wordt niet meer weergegeven.
  4. Ga naar API-machtigingen>Voeg een machtiging>mijn API's toe.
    • Selecteer MyService.ApiService.
    • Selecteer access_as_user>machtigingen toevoegen.
    • Selecteer Beheerderstoestemming verlenen voor [tenant] (of gebruikers worden bij eerste gebruik gevraagd).
  5. Kopieer de toepassings-id (client) voor de web-app appsettings.json.

Opmerking

Sommige organisaties staan geen clientgeheimen toe. Zie Certificaatreferenties of certificaatloze verificatie voor alternatieven.

Zie Quickstart: Een toepassing registreren voor meer informatie.

Stap 3: Configuratie bijwerken

Nadat u de app-registraties hebt gemaakt, werkt u uw appsettings.json bestanden bij:

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

Sla het geheim veilig op:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Waarde Waar vind ik?
TenantId Microsoft Entra-beheercentrum > Overzicht > Tenant ID
API ClientId App-registraties > MyService.ApiService > Applicatie (client) ID
Web ClientId App-registraties > MyService.Web > Toepassings-ID (client)
Client Secret Gemaakt in stap 2 (direct kopiëren wanneer deze is gemaakt)

Opmerking

Met de starterssjabloon Aspire wordt automatisch een WeatherApiClient klasse in het MyService.Web project gemaakt. Deze getypte HttpClient wordt in deze handleiding gebruikt om de beveiligde API aan te roepen. U hoeft deze klasse niet zelf te maken. Deze maakt deel uit van de sjabloon.


Snel aan de slag

Deze sectie bevat een beknopte verwijzing voor het toevoegen van verificatie. Zie deel 1 en deel 2 voor gedetailleerde overzichten.

API (MyService.ApiService)

Installeer de Microsoft. Identity.Web NuGet-pakket:

dotnet add package Microsoft.Identity.Web

Voeg de Microsoft Entra-configuratie toe aan appsettings.json:

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

Verificatie en autorisatie registreren 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)

Installeer de Microsoft. Identity.Web NuGet-pakket:

dotnet add package Microsoft.Identity.Web

Voeg de Microsoft Entra-configuratie toe aan 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"] }
}

Configureer verificatie, token acquisitie en de downstream-API-client 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();

De MicrosoftIdentityMessageHandler tokens worden automatisch verkregen en gekoppeld en BlazorAuthenticationChallengeHandler verwerkt toestemmings- en voorwaardelijke toegangsproblemen.

Belangrijk

Vergeet niet om UserInfo.razor aan te maken voor de aanmeldingsknop. Zie Blazor UI-onderdelen toevoegen voor meer informatie.

Opmerking

BlazorAuthenticationChallengeHandler en LoginLogoutEndpointRouteBuilderExtensions worden geleverd in Microsoft.Identity.Web (v3.3.0+). Er is geen bestandskopie vereist.


Bestanden identificeren die moeten worden gewijzigd

De volgende tabel bevat de bestanden die u in elk project wijzigt:

Project Bestand Changes
ApiService Program.cs JWT Bearer-verificatie, autorisatie-middleware
appsettings.json configuratie van Microsoft Entra
.csproj Microsoft.Identity.Web toevoegen
Web Program.cs OIDC-verificatie, verkrijging van token, BlazorAuthenticationChallengeHandler
appsettings.json Microsoft Entra configuratie, downstream-API-bereiken
.csproj Voeg Microsoft.Identity.Web toe (v3.3.0+)
Components/UserInfo.razor Gebruikersinterface voor aanmeldingsknop (nieuw bestand)
Components/Layout/MainLayout.razor Het onderdeel UserInfo opnemen
Components/Routes.razor AutoriserenRouteView voor beveiligde pagina's
Pagina's die API's aanroepen Uitproberen/vangen met ChallengeHandler

Inzicht in de verificatiestroom

In het volgende diagram ziet u hoe de Blazor-front-end, Microsoft Entra en de beveiligde API communiceren:

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. Gebruiker bezoekt Blazor-app → Niet geauthenticeerd → ziet de knop "Aanmelden".
  2. Gebruiker selecteert Login → Wordt doorgestuurd naar /authentication/login → OIDC-uitdaging → Microsoft Entra.
  3. Gebruiker meldt zich aan → Microsoft Entra voert een redirect uit naar /signin-oidc → cookie ingesteld.
  4. Gebruiker navigeert naar de weerpagina → Blazor roept aan WeatherApiClient.GetAsync().
  5. MicrosoftIdentityMessageHandler onderschept de aanvraag, verwerft een token uit de cache (of vernieuwt op de achtergrond) en voegt de Authorization: Bearer <token> header toe.
  6. API ontvangt aanvraag → Microsoft. Identity.Web valideert de JWT-→ retourneert gegevens.
  7. Blazor geeft weergegevens weer.

De oplossingsstructuur controleren

Met de starterssjabloon Aspire wordt de volgende projectindeling gemaakt:

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

Deel 1: De API-back-end beveiligen met Microsoft. Identity.Web

In deze sectie wordt het API-project geconfigureerd om JWT Bearer-tokens te valideren die zijn uitgegeven door Microsoft Entra.

Voeg Microsoft toe. Identity.Web-pakket

Voer de volgende opdracht uit om het Microsoft.Identity.Web NuGet-pakket te installeren:

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

Instellingen voor Microsoft Entra configureren

Voeg de Microsoft Entra-configuratie toe aan 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": "*"
}

Belangrijkste eigenschappen:

  • ClientId: registratie-id van api-app Microsoft Entra
  • TenantId: uw Microsoft Entra-tenant-id of "organizations" voor multi-tenant of "common" voor elke Microsoft-account
  • Audiences: Geldige token-doelgroepen (meestal uw App-ID-URI)

API-Program.cs bijwerken

Vervang de inhoud van MyService.ApiService/Program.cs door de volgende code om JWT Bearer-verificatie toe te voegen en eindpunten te beveiligen:

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

Belangrijke wijzigingen:

  • JWT Bearer-verificatie registreren bij AddMicrosoftIdentityWebApi
  • Voeg app.UseAuthentication() en app.UseAuthorization() middleware toe
  • Toepassen .RequireAuthorization() op beveiligde eindpunten

De beveiligde API testen

Controleer of de API niet-geverifieerde aanvragen weigert en geldige tokens accepteert.

Een aanvraag zonder token verzenden:

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

Een aanvraag met een geldig token verzenden:

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

Deel 2: Blazor-front-end configureren voor verificatie

De Blazor Server-app maakt gebruik van Microsoft. Identity.Web voor:

  • Gebruikers aanmelden met OIDC
  • Toegangstokens verkrijgen om de API aan te roepen
  • Tokens koppelen aan uitgaande HTTP-aanvragen

Voeg Microsoft toe. Identity.Web-pakket

Voer de volgende commando uit om het Microsoft.Identity.Web NuGet-pakket te installeren:

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

Instellingen voor Microsoft Entra configureren

Voeg de Microsoft Entra-configuratie en downstream-API-bereiken toe aan 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": "*"
}

Configuratiedetails:

  • ClientId: Registratie-id van web-app (niet de API-id)
  • ClientCredentials: Referenties voor de webapp om tokens te verkrijgen. Ondersteunt meerdere referentietypen. Zie het overzicht van referenties voor opties die gereed zijn voor productie.
  • Scopes: moet overeenkomen met de app-id-URI van de API met /.default achtervoegsel

Waarschuwing

Gebruik voor productie certificaten of beheerde identiteit in plaats van clientgeheimen. Zie Certificaatloze verificatie voor de aanbevolen benadering.

Web-app-Program.cs bijwerken

Vervang de inhoud van MyService.Web/Program.cs met de volgende code om OIDC-authenticatie, tokenverwerking en de downstream API-client te configureren.

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

Belangrijkste punten:

  • AddMicrosoftIdentityWebApp: Hiermee configureert u OIDC-verificatie
  • EnableTokenAcquisitionToCallDownstreamApi: Hiermee schakelt u tokenverwerving in voor downstream-API's
  • AddScoped<BlazorAuthenticationChallengeHandler>: verwerkt incrementele toestemming en voorwaardelijke toegang in Blazor Server
  • AddMicrosoftIdentityMessageHandler: Bearer-tokens automatisch koppelen aan HttpClient-aanvragen
  • https+http://apiservice: Aspire service-ontdekking zet dit om naar de werkelijke API-URL
  • Middlewarevolgorde: UseAuthentication()UseAuthorization() → eindpunten

De AddMicrosoftIdentityMessageHandler extensie ondersteunt meerdere configuratiepatronen:

Optie 1: Configuratie van appsettings.json (eerder weergegeven)

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

Optie 2: Inline-configuratie met Action-delegate

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

Optie 3: Configuratie per aanvraag (parameterloos)

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

Blazor UI-onderdelen toevoegen

Belangrijk

Deze stap wordt vaak vergeten. Zonder het onderdeel UserInfo kunnen gebruikers zich niet aanmelden.

BlazorAuthenticationChallengeHandler en LoginLogoutEndpointRouteBuilderExtensions worden geleverd in Microsoft.Identity.Web v3.3.0+. Ze zijn automatisch beschikbaar zodra u naar het pakket verwijst. Er is geen bestandskopie vereist.

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

Toevoegen aan indeling: Integreer <UserInfo /> in uw 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>

Routes.razor bijwerken voor AuthorizeRouteView

Vervangen RouteView door 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>

Uitzonderingen verwerken op pagina's die API's aanroepen

Blazor Server vereist expliciete afhandeling van uitzonderingen voor voorwaardelijke toegang en toestemming. U moet MicrosoftIdentityWebChallengeUserException verwerken op elke pagina die een downstream-API aanroept, tenzij uw app vooraf is geverifieerd en u alle scopes van tevoren aanvraagt in Program.cs.

In het volgende Weather.razor voorbeeld ziet u de juiste afhandeling van uitzonderingen:

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

Het patroon werkt als volgt:

  1. IsAuthenticatedAsync() controleert of de gebruiker is aangemeld voordat de API-aanroepen worden uitgevoerd.
  2. HandleExceptionAsync() vangt MicrosoftIdentityWebChallengeUserException (of als InnerException).
  3. Als het een challenge-exceptie is, wordt de gebruiker omgeleid om opnieuw te verifiëren met de vereiste claims of scopes.
  4. Als het geen uitzondering op een uitdaging is, retourneert HandleExceptionAsyncfalse zodat u de fout zelf kunt afhandelen.

Clientgeheim opslaan in gebruikersgeheimen

Gebruik de .NET Secret Manager om het clientgeheim veilig op te slaan tijdens de ontwikkeling.

Waarschuwing

Voer nooit geheimen door aan broncodebeheer.

Initialiseer gebruikersgeheimen en sla het clientgeheim op:

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

Update dan appsettings.json om het hardcoded geheim te verwijderen.

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

Microsoft. Identity.Web ondersteunt meerdere referentietypen. Zie referentieoverzicht voor productie.


De implementatie controleren

Gebruik deze controlelijst om te bevestigen dat u alle vereiste stappen hebt voltooid.

API-project

  • [ ] Microsoft.Identity.Web-pakket toegevoegd
  • [ ] Bijgewerkt appsettings.json met AzureAd sectie
  • [ ] Bijgewerkt Program.cs met AddMicrosoftIdentityWebApi
  • [ ] Toegevoegd .RequireAuthorization() aan beveiligde eindpunten

Web/Blazor-project

  • [ ] Toegevoegd Microsoft.Identity.Web-pakket (v3.3.0+)
  • [ ] Bijgewerkt appsettings.json met de secties AzureAd en WeatherApi
  • [ ] Bijgewerkt Program.cs met OIDC, tokenverwerking
  • [ ] Toegevoegd AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Aangemaakt Components/UserInfo.razor (de login-knop)
  • [ ] MainLayout.razor bijgewerkt om <UserInfo /> op te nemen.
  • [ ] Bijgewerkt Routes.razor met AuthorizeRouteView
  • [ ] Try/catch met ChallengeHandler toegevoegd op elke pagina die API's aanroept
  • [ ] Clientgeheim opgeslagen in gebruikersgeheimen

Verificatie

  • [ ] dotnet build slaagt
  • [ ] App-registraties gemaakt in het Microsoft Entra-beheercentrum
  • [ ] appsettings.json heeft echte GUID's (geen tijdelijke aanduidingen)

Testen en problemen oplossen

Nadat u de implementatie hebt voltooid, voert u de toepassing uit en controleert u de end-to-end-verificatiestroom.

De toepassing uitvoeren

Start de Aspire AppHost om zowel de web- als API-projecten te starten:

# From solution root
dotnet restore
dotnet build

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

De verificatiestroom testen

  1. Open de browser → Blazor Web UI (controleer het Aspire-dashboard op URL).
  2. Selecteer Login → Meld u aan met Microsoft Entra.
  3. Navigeer naar de pagina Weer .
  4. Controleer of de weergegevens geladen worden (van een beveiligde API).

Algemene problemen oplossen

De volgende tabel bevat veelvoorkomende problemen en de bijbehorende oplossingen:

Issue Solution
401 bij API-aanroepen Bereiken controleren in appsettings.json overeenstemming met de app-id-URI van de API
OIDC-omleiding mislukt Voeg /signin-oidc toe aan de Microsoft Entra-omleidings-URI
Token niet gekoppeld Zorg ervoor dat AddMicrosoftIdentityMessageHandler wordt aangeroepen op de HttpClient
Servicedetectie mislukt Controleer AppHost.cs verwijzingen naar beide projecten en zorg dat ze actief zijn.
AADSTS65001 Beheerderstoestemming vereist: toestemming verlenen in de Microsoft Entra-beheercentrum
Geen aanmeldingsknop Controleren of UserInfo.razor deze bestaat en is opgenomen in MainLayout.razor
Toestemmingslus Zorg ervoor dat try/catch met HandleExceptionAsync aanwezig is op alle pagina's voor API-aanroepen.

MSAL-logboekregistratie inschakelen

Bij het oplossen van verificatieproblemen schakelt u gedetailleerde MSAL-logboekregistratie in om details van tokenovername te bekijken. Voeg de volgende logboekniveaus toe aan appsettings.json:

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

Waarschuwing

Schakel logboekregistratie voor foutopsporing in productie uit omdat dit zeer uitgebreid kan zijn.

Tokens inspecteren

Als u tokenproblemen wilt opsporen, decodert u uw JWT op jwt.ms en controleert u het volgende:

  • aud (doelgroep): komt overeen met de client-id of app-id-URI van uw API
  • iss (uitgever): komt overeen met uw tenant (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (scopes): bevat de vereiste scopes
  • exp (vervaldatum): token is niet verlopen

Algemene scenario's verkennen

In de volgende secties ziet u hoe u de basis-implementatie kunt uitbreiden voor aanvullende gebruiksvoorbeelden.

Blazor-pagina's beveiligen

Voeg het [Authorize] kenmerk toe aan pagina's waarvoor verificatie is vereist:

@page "/weather"
@attribute [Authorize]

Of definieer autorisatiebeleid in Program.cs:

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

Bereiken valideren in de API

Zorg ervoor dat de API alleen tokens met specifieke rechten accepteert door deze te koppelen met RequireScope.

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

App-alleen-tokens gebruiken (service-naar-service)

Voor daemon-scenario's of service-naar-service-aanroepen zonder gebruikerscontext, ingesteld RequestAppToken op 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;
});

Certificaatloze referenties gebruiken voor productie

Gebruik voor productie-implementaties in Azure beheerde identiteit in plaats van clientgeheimen. Configureer de ClientCredentials sectie als volgt:

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

Zie Verificatie zonder certificaat voor meer informatie.

Downstream-API's aanroepen vanuit de API (namens een ander)

Als uw API namens de gebruiker een andere downstream-API moet aanroepen, schakelt u het verkrijgen van tokens namens de gebruiker in via 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"));

Voeg de downstream-API-configuratie toe aan appsettings.json:

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

Roep vervolgens de downstream-API aan vanaf een eindpunt:

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

Zie Downstream-API's aanroepen voor meer informatie.