Lägga till Microsoft Entra ID-autentisering i en .NET Aspire app

Den här guiden visar hur du skyddar ett .NET Aspire distribuerat program med Microsoft Entra ID autentisering och auktorisering. Den omfattar:

  1. Blazor Server-klientdel (MyService.Web): Användarinloggning med OpenID Connect och tokenförvärv
  2. Protected API-backend (MyService.ApiService): JWT-validering med hjälp av Microsoft.Identity.Web
  3. Flöde från slutpunkt till slutpunkt: Blazor hämtar åtkomsttoken och anropar det skyddade API:et med Aspire-tjänstidentifiering

Den här guiden förutsätter att du började med ett Aspire-projekt som skapats med hjälp av följande kommando:

aspire new aspire-starter --name MyService

Förutsättningar

Tips/Råd

Är du nybörjare på Aspire? Se .NET Aspire översikt.

Förstå arbetsflödet i två faser

Den här guiden följer en tvåfasmetod:

Fas Vad händer Result
Fas 1 Lägg till autentiseringskod med platshållarvärden Appversioner men körs inte
Fas 2 Etablera Microsoft Entra appregistreringar Appen körs med verklig autentisering

Registrera appar i Microsoft Entra ID

Innan appen kan autentisera användare behöver du två appregistreringar i Microsoft Entra:

Appregistrering Avsikt Nyckelkonfiguration
API (MyService.ApiService) Validerar inkommande token App-ID-URI, access_as_user omfång
Webbapp (MyService.Web) Loggar in användare, hämtar token Omdirigerings-URI:er, klienthemlighet, API-behörigheter

Om du redan har konfigurerat appregistreringar behöver du följande värden för :appsettings.json

  • TenantId – ditt Microsoft Entra klient-ID
  • API ClientId – program-ID (klient)-ID för din API-appregistrering
  • API App ID URI – vanligtvis api://<api-client-id> (används i Audiences och Scopes)
  • Web App ClientId – Program-ID (klient)-ID för din webbappsregistrering
  • Klienthemlighet (eller certifikat) – Autentiseringsuppgifter för webbappen (lagra i användarhemligheter, inte appsettings.json)
  • Omfång – de omfång som din webbapp begär, till exempel api://<api-client-id>/.default eller api://<api-client-id>/access_as_user.

Steg 1: Registrera API:et

  1. Gå till Microsoft Entra administrationscenter>Identity>Applications>App registrations.
  2. Välj Ny registrering.
    • Namn:MyService.ApiService
    • Kontotyper som stöds: Endast konton i den här organisationskatalogen (enskild klientorganisation)
    • Välj Registrera.
  3. Gå till Exponera ett API>Lägg till bredvid Program-ID URI.
    • Acceptera standardvärdet (api://<client-id>) eller anpassa det.
    • Välj Lägg till ett omfång:
      • Omfångsnamn:access_as_user
      • Vem kan samtycka: Administratörer och användare
      • Visningsnamn för administratörsmedgivande: Åtkomst till MyService-API
      • Beskrivning av administratörsmedgivande: Tillåter att appen får åtkomst till MyService API för den inloggade användarens räkning.
      • Välj Lägg till definitionsområde.
  4. Kopiera program-ID :t (klient) – du behöver det här för båda appsettings.json filerna.

Mer information finns i Snabbstart: Konfigurera en app för att exponera ett webb-API.

Steg 2: Registrera webbappen

  1. Gå till App registrations>Ny registrering.
    • Namn:MyService.Web
    • Kontotyper som stöds: Endast konton i den här organisationskatalogen
    • Omdirigerings-URI: Välj Webb och ange appens URL + /signin-oidc
      • För lokal utveckling: https://localhost:7001/signin-oidc (kontrollera din launchSettings.json för den faktiska porten)
    • Välj Registrera.
  2. Gå till Autentisering>Lägg till URI för att lägga till alla dina utvecklings-URL:er (från launchSettings.json).
  3. Gå till Certifikat och hemligheter>Klienthemligheter>Ny klienthemlighet.
    • Lägg till en beskrivning och förfallodatum.
    • Kopiera det hemliga värdet omedelbart – det visas inte igen.
  4. Gå till API-behörigheter>Lägg till en behörighet>Mina API:er.
    • Välj MyService.ApiService.
    • Välj access_as_user>Lägg till behörigheter.
    • Välj Bevilja administratörsmedgivande för [klient] (eller användarna uppmanas att göra det vid första användningen).
  5. Kopiera program-ID (klient) för webbappenappsettings.json.

Anmärkning

Vissa organisationer tillåter inte klienthemligheter. Alternativ finns i Certifikatautentiseringsuppgifter eller Certifikatlös autentisering.

Mer information finns i Snabbstart: Registrera ett program.

Steg 3: Uppdatera konfigurationen

När du har skapat appregistreringarna uppdaterar du filerna appsettings.json :

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

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

Lagra hemligheten på ett säkert sätt:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Värde Var du hittar
TenantId Microsoft Entra administrationscenter > Översikt > Klient-ID
API ClientId App-registreringar > MyService.ApiService > Program (klient) ID
Web ClientId Appregistreringar > MyService.Web > Applikation (klient) ID
Client Secret Skapad i steg 2 (kopiera omedelbart när den skapas)

Anmärkning

Aspire Starter-mallen skapar automatiskt en WeatherApiClient klass i MyService.Web projektet. Den här typen av HttpClient används i den här guiden för att demonstrera anrop till det skyddade API:et. Du behöver inte skapa den här klassen själv – den är en del av mallen.


Kom igång snabbt

Det här avsnittet innehåller en komprimerad referens för att lägga till autentisering. Detaljerade genomgångar finns i del 1 och del 2.

API (MyService.ApiService)

Installera Microsoft. Identity.Web NuGet-paket:

dotnet add package Microsoft.Identity.Web

Lägg till konfigurationen Microsoft Entra i appsettings.json:

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

Registrera autentisering och auktorisering i Program.cs:

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

Webbapp (MyService.Web)

Installera Microsoft. Identity.Web NuGet-paket:

dotnet add package Microsoft.Identity.Web

Lägg till konfigurationen Microsoft Entra i 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"] }
}

Konfigurera autentisering, tokenförvärv och den underordnade API-klienten i 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();

Den MicrosoftIdentityMessageHandler hämtar och bifogar token automatiskt, och BlazorAuthenticationChallengeHandler hanterar utmaningar för medgivande och villkorsstyrd åtkomst.

Viktigt!

Glöm inte att skapa UserInfo.razor för inloggningsknappen. Mer information finns i Lägga till Blazor UI-komponenter .

Anmärkning

BlazorAuthenticationChallengeHandler och LoginLogoutEndpointRouteBuilderExtensions levereras i Microsoft.Identity.Web (v3.3.0+). Ingen filkopiering krävs.


Identifiera filer som ska ändras

I följande tabell visas de filer som du ändrar i varje projekt:

Projekt Arkiv Changes
ApiService Program.cs JWT Bearer-autentisering, mellanprogram för auktorisering
appsettings.json Microsoft Entra-konfiguration
.csproj Lägg till Microsoft.Identity.Web
Webb Program.cs OIDC-autentisering, tokenförvärv, BlazorAuthenticationChallengeHandler
appsettings.json Microsoft Entra konfiguration, underordnade API-omfång
.csproj Lägg till Microsoft.Identity.Web (v3.3.0+)
Components/UserInfo.razor Användargränssnitt för inloggningsknappen (ny fil)
Components/Layout/MainLayout.razor Inkludera UserInfo-komponenten
Components/Routes.razor AuthorizeRouteView för skyddade sidor
Sidor som anropar API:er Prova/fånga med ChallengeHandler

Förstå autentiseringsflödet

Följande diagram visar hur Blazor-klientdelen, Microsoft Entra och det skyddade API:et interagerar:

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. Användaren besöker Blazor-appen → Inte autentiserad → ser knappen "Inloggning".
  2. Användare väljer Inloggning → Omdirigeringar till /authentication/login → OIDC-utmaning → Microsoft Entra.
  3. Användare loggar in → Microsoft Entra omdirigerar till /signin-oidc → cookie upprättad.
  4. Användaren navigerar till sidan Väder → Blazor anropar WeatherApiClient.GetAsync().
  5. MicrosoftIdentityMessageHandler fångar upp begäran, hämtar en token från cacheminnet (eller förnyar den tyst) och bifogar Authorization: Bearer <token> huvud.
  6. API tar emot begäran → Microsoft. Identity.Web verifierar JWT-→ returnerar data.
  7. Blazor renderar väderdata.

Granska lösningsstrukturen

Mallen Aspire Starter skapar följande 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

Del 1: Skydda API-serverdelen med Microsoft. Identity.Web

Det här avsnittet konfigurerar API-projektet för att verifiera JWT Bearer-token som utfärdats av Microsoft Entra.

Lägg till Microsoft. Identity.Web-paket

Kör följande kommando för att installera Microsoft. Identity.Web NuGet-paket:

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

Konfigurera Microsoft Entra inställningar

Lägg till konfigurationen Microsoft Entra i 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": "*"
}

Viktiga egenskaper:

  • ClientId: Microsoft Entra API-appregistrerings-ID
  • TenantId: Ditt Microsoft Entra klient-ID eller "organizations" för fleranvändar eller "common" för alla Microsoft-konto
  • Audiences: Giltiga tokenmålgrupper (vanligtvis din app-ID-URI)

Uppdatera API Program.cs

Ersätt innehållet i MyService.ApiService/Program.cs med följande kod för att lägga till JWT Bearer-autentisering och skydda slutpunkter:

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

Viktiga ändringar:

  • Registrera JWT Bearer-autentisering med AddMicrosoftIdentityWebApi
  • Lägg till app.UseAuthentication() och app.UseAuthorization() mellanprogram
  • Tillämpa .RequireAuthorization() på skyddade slutpunkter

Testa det skyddade API:et

Kontrollera att API:et avvisar oautentiserade begäranden och accepterar giltiga token.

Skicka en begäran utan token:

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

Skicka en begäran med en giltig token:

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

Del 2: Konfigurera Blazor-klientdelen för autentisering

Blazor Server-appen använder Microsoft. Identity.Web till:

  • Logga in användare med OIDC
  • Hämta åtkomsttoken för att anropa API:et
  • Koppla token till utgående HTTP-begäranden

Lägg till Microsoft. Identity.Web-paket

Kör följande kommando för att installera Microsoft. Identity.Web NuGet-paket:

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

Konfigurera Microsoft Entra inställningar

Lägg till Microsoft Entra-konfiguration och underordnade API-omfång i 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": "*"
}

Konfigurationsinformation:

  • ClientId: Registrerings-ID för webbappar (inte API-ID:t)
  • ClientCredentials: Autentiseringsuppgifter för webbappen för att hämta token. Stöder flera typer av autentiseringsuppgifter. Se Översikt över autentiseringsuppgifter för produktionsklara alternativ.
  • Scopes: Måste matcha API:ets app-ID-URI med /.default suffix

Varning

För produktion använder du certifikat eller hanterad identitet i stället för klienthemligheter. Se Certifikatfri autentisering för den rekommenderade metoden.

Uppdatera webbappens Program.cs

Ersätt innehållet i MyService.Web/Program.cs med följande kod för att konfigurera OIDC-autentisering, tokenförvärv och den underordnade API-klienten:

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

Viktiga punkter:

  • AddMicrosoftIdentityWebApp: Konfigurerar OIDC-autentisering
  • EnableTokenAcquisitionToCallDownstreamApi: Aktiverar tokenförvärv för underordnade API:er
  • AddScoped<BlazorAuthenticationChallengeHandler>: Hanterar inkrementellt medgivande och villkorlig åtkomst i Blazor Server
  • AddMicrosoftIdentityMessageHandler: Kopplar ägartoken till HttpClient-begäranden automatiskt
  • https+http://apiservice: Aspire-tjänstidentifiering omvandlar detta till den faktiska API-URL:en
  • Mellanprogramsordning: UseAuthentication()UseAuthorization() → slutpunkter

Tillägget AddMicrosoftIdentityMessageHandler stöder flera konfigurationsmönster:

Alternativ 1: Konfiguration från appsettings.json (visas tidigare)

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

Alternativ 2: Inlinekonfiguration med Action-delegat

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

Alternativ 3: Konfiguration per begäran (parameterlös)

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

Lägga till Blazor UI-komponenter

Viktigt!

Det här steget glöms ofta bort. Utan UserInfo-komponenten kan användarna inte logga in.

BlazorAuthenticationChallengeHandler och LoginLogoutEndpointRouteBuilderExtensions i Microsoft. Identity.Web v3.3.0+. De är automatiskt tillgängliga när du refererar till paketet – ingen filkopiering krävs.

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

Lägg till i layout: Inkludera <UserInfo /> i :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>

Uppdatera Routes.razor för AuthorizeRouteView

Ersätt RouteView med AuthorizeRouteView i 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>

Hantera undantag på sidor som anropar API:er

Blazor Server kräver explicit undantagshantering för villkorsstyrd åtkomst och medgivande. Du måste hantera MicrosoftIdentityWebChallengeUserException på varje sida som anropar ett underordnat API, såvida inte appen är förauktoriserad och du begär alla auktoriseringar i förväg i Program.cs.

I följande Weather.razor exempel visas korrekt undantagshantering:

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

Mönstret fungerar på följande sätt:

  1. IsAuthenticatedAsync() kontrollerar om användaren är inloggad innan api-anrop görs.
  2. HandleExceptionAsync() fångar MicrosoftIdentityWebChallengeUserException (eller som InnerException).
  3. Om det är ett utmaningsundantag, omdirigeras användaren för att autentisera sig igen med de anspråk eller omfång som krävs.
  4. Om det inte är ett utmaningsfel HandleExceptionAsync returneras false så att du kan hantera felet själv.

Lagra klienthemligheter i användarhemligheter

Använd .NET Secret Manager för att lagra klienthemligheten på ett säkert sätt under utvecklingen.

Försiktighet

Checka aldrig in känslig information i källkontrollen.

Initiera användarhemligheter och lagra klienthemligheten:

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

Uppdatera appsettings.json sedan för att ta bort den hårdkodade hemligheten:

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

Microsoft. Identity.Web stöder flera typer av autentiseringsuppgifter. Information om produktion finns i Översikt över autentiseringsuppgifter.


Verifiera implementeringen

Använd den här checklistan för att bekräfta att du har slutfört alla nödvändiga steg.

API-projekt

  • [ ] Lade till Microsoft.Identity.Web-paketet
  • [ ] Uppdaterade appsettings.json med avsnittet AzureAd
  • [ ] Uppdaterad Program.cs med AddMicrosoftIdentityWebApi
  • [ ] Lagt till .RequireAuthorization() i skyddade slutpunkter

Webb-/Blazor-projekt

  • [ ] Lade till Microsoft.Identity.Web-paketet (v3.3.0+)
  • [ ] Uppdaterad appsettings.json med avsnitten AzureAd och WeatherApi
  • [ ] Uppdaterad Program.cs med OIDC, tokenhämtning
  • [ ] Har lagts till AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Skapat Components/UserInfo.razor (inloggningsknappen)
  • [ ] Uppdaterad MainLayout.razor för att inkludera <UserInfo />
  • [ ] Uppdaterad Routes.razor med AuthorizeRouteView
  • [ ] Lade till try/catch med ChallengeHandler på varje sida som anropar API:er
  • [ ] Lagrad klienthemlighet i användarhemligheter

Verification

  • [ ] dotnet build lyckas
  • [ ] Appregistreringar som skapats i Microsoft Entra Administrationscenter
  • [ ] appsettings.json har verkliga GUID:er (inga platshållare)

Testa och felsöka

När du har slutfört implementeringen kör du programmet och verifierar autentiseringsflödet från slutpunkt till slutpunkt.

Starta programmet

Starta Aspire AppHost för att starta både webb- och API-projekten:

# From solution root
dotnet restore
dotnet build

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

Testa autentiseringsflödet

  1. Öppna webbläsaren → Blazor Web UI (se Aspire-instrumentpanelen för URL).
  2. Välj Login → Logga in med Microsoft Entra.
  3. Gå till sidan Väder .
  4. Verifiera väderdatainläsningar (från skyddat API).

Lösa vanliga problem

I följande tabell visas vanliga problem och deras lösningar:

Problematik Lösning
401 på API-anrop Kontrollera omfången i appsettings.json matchar API:ets app-ID-URI
OIDC-omdirigering misslyckas Lägg till /signin-oidc i Microsoft Entra omdirigerings-URI:er
Token är inte bifogat Se till att AddMicrosoftIdentityMessageHandler anropas på HttpClient
Tjänstidentifieringen misslyckas Kontrollera AppHost.cs referenser till båda projekten eftersom de redan är igång.
AADSTS65001 Administratörsmedgivande krävs – bevilja medgivande i Microsoft Entra administrationscenter
Ingen inloggningsknapp Se till att UserInfo.razor finns och ingår i MainLayout.razor
Medgivandeslinga Kontrollera att try/catch with HandleExceptionAsync finns på alla API-anropande sidor

Aktivera MSAL-loggning

När du felsöker autentiseringsproblem aktiverar du detaljerad MSAL-loggning för att se information om tokenförvärv. Lägg till följande loggnivåer i appsettings.json:

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

Varning

Inaktivera felsökningsloggning i produktion eftersom det kan vara mycket utförligt.

Inspektera token

Om du vill felsöka tokenproblem avkodar du din JWT på jwt.ms och verifierar:

  • aud (målgrupp): Matchar ditt API:s klient-ID eller app-ID-URI
  • iss (utfärdare): Matchar din klientorganisation (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (omfång): Innehåller de nödvändiga omfången
  • exp (förfallodatum): Token har inte upphört att gälla

Utforska vanliga scenarier

Följande avsnitt visar hur du utökar basimplementeringen för ytterligare användningsfall.

Skydda Blazor-sidor

[Authorize] Lägg till attributet på sidor som kräver autentisering:

@page "/weather"
@attribute [Authorize]

Eller definiera auktoriseringsprinciper i Program.cs:

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

Verifiera omfång i API:et

Se till att API:et endast accepterar token med specifika omfång genom att RequireScopelänka :

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

Använd endast app-nycklar (tjänst-till-tjänst)

För daemonscenarier eller tjänst-till-tjänst-anrop utan användarkontext anger du RequestAppToken till 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;
});

Använda certifikatlösa autentiseringsuppgifter för produktion

För produktionsdistributioner i Azure använder du hanterad identitet i stället för klienthemligheter. Konfigurera ClientCredentials avsnittet enligt följande:

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

Mer information finns i Certifikatfri autentisering.

Anropa underordnade API:er från API:et (å uppdrag av)

Om ditt API behöver anropa ett annat nedströms-API på uppdrag av användaren, aktiverar du på uppdrag av-tokenanskaffning i 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"));

Lägg till den underordnade API-konfigurationen i appsettings.json:

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

Anropa sedan det underordnade API:et från en slutpunkt:

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

Mer information finns i Anropa nedströms-API:er.