Menambahkan autentikasi Microsoft Entra ID ke aplikasi .NET Aspire

Panduan ini menunjukkan cara mengamankan aplikasi terdistribusi .NET Aspire dengan autentikasi dan otorisasi Microsoft Entra ID. Ini mencakup:

  1. Frontend Blazor Server (MyService.Web): Pengguna masuk dengan OpenID Connect dan akuisisi token
  2. Protected API backend (MyService.ApiService): Validasi JWT menggunakan Microsoft. Identity.Web
  3. Alur end-to-end: Blazor memperoleh token akses dan memanggil API yang dilindungi dengan penemuan layanan Aspire

Panduan ini mengasumsikan Anda memulai dengan proyek Aspire yang dibuat dengan menggunakan perintah berikut:

aspire new aspire-starter --name MyService

Prasyarat

Petunjuk / Saran

Baru di Aspire? Lihat ringkasan .NET Aspire.

Memahami alur kerja dua fase

Panduan ini mengikuti pendekatan dua fase:

Fase Apa yang terjadi Result
Fase 1 Menambahkan kode autentikasi dengan nilai tempat penampung Aplikasi berhasil dibangun namun tidak dapat dijalankan
Fase 2 Menyiapkan pendaftaran aplikasi Microsoft Entra Aplikasi berjalan dengan autentikasi nyata

Mendaftarkan aplikasi di Microsoft Entra ID

Sebelum aplikasi dapat mengautentikasi pengguna, Anda memerlukan dua pendaftaran aplikasi di Microsoft Entra:

Pendaftaran Aplikasi Kegunaan Konfigurasi kunci
API (MyService.ApiService) Memvalidasi token masuk URI ID Aplikasi, access_as_user cakupan
Aplikasi Web (MyService.Web) Masuk pengguna, memperoleh token URI pengalihan, rahasia klien, izin API

Jika Anda sudah mengonfigurasi pendaftaran aplikasi, Anda memerlukan nilai-nilai ini untuk appsettings.json:

  • TenantId — ID penyewa Microsoft Entra Anda
  • API ClientId — ID Aplikasi (klien) pendaftaran aplikasi API Anda
  • URI ID Aplikasi API — Biasanya api://<api-client-id> (digunakan dalam Audiences dan Scopes)
  • Web App ClientId — ID Aplikasi (klien) pendaftaran aplikasi web Anda
  • Rahasia Klien (atau sertifikat) — Kredensial untuk aplikasi web (simpan dalam rahasia pengguna, bukan appsettings.json)
  • Cakupan — Cakupan yang diminta oleh aplikasi web Anda, misalnya, api://<api-client-id>/.default atau api://<api-client-id>/access_as_user

Langkah 1: Daftarkan API

  1. Pergi ke pusat admin Microsoft Entra>Identity>Aplikasi>Pendaftaran aplikasi.
  2. Pilih Pendaftaran baru.
    • Nama: MyService.ApiService
    • Jenis akun yang didukung: Akun dalam direktori organisasi ini saja (Penyewa tunggal)
    • Pilih Daftarkan.
  3. Buka Mengekspos API>Tambahkan di samping URI ID Aplikasi.
    • Terima default (api://<client-id>) atau sesuaikan.
    • Pilih Tambahkan cakupan:
      • Nama cakupan:access_as_user
      • Siapa yang dapat menyetujui: Admin dan pengguna
      • Nama tampilan persetujuan admin: Mengakses MYService API
      • Deskripsi persetujuan admin: Memungkinkan aplikasi mengakses MYService API atas nama pengguna yang masuk.
      • Pilih Tambahkan cakupan.
  4. Salin ID Aplikasi (klien) — Anda akan memerlukan ini untuk kedua appsettings.json file.

Untuk informasi selengkapnya, lihat Mulai Cepat: Mengonfigurasi aplikasi untuk mengekspos API web.

Langkah 2: Daftarkan aplikasi web

  1. Buka Pendaftaran aplikasi>Pendaftaran baru.
    • Nama: MyService.Web
    • Jenis akun yang didukung: Akun dalam direktori organisasi ini saja
    • URI Pengalihan: Pilih Web dan masukkan URL aplikasi Anda + /signin-oidc
      • Untuk pengembangan lokal: https://localhost:7001/signin-oidc (periksa port aktual Anda launchSettings.json )
    • Pilih Daftarkan.
  2. Buka Autentikasi>Tambahkan URI untuk menambahkan semua URL pengembangan Anda (dari launchSettings.json).
  3. Buka Sertifikat & rahasiaRahasia klienRahasia klien baru.
    • Tambahkan deskripsi dan kedaluwarsa.
    • Salin nilai rahasia segera — nilai tersebut tidak akan ditampilkan lagi.
  4. Buka Izin> APITambahkan izin>API Saya.
    • Pilih MyService.ApiService.
    • Pilih access_as_user>Tambahkan izin.
    • Pilih Berikan persetujuan admin untuk [penyewa] (atau pengguna diminta pada penggunaan pertama).
  5. Salin ID Aplikasi (klien) untuk aplikasi appsettings.jsonweb .

Nota

Beberapa organisasi tidak mengizinkan rahasia klien. Untuk alternatif, lihat Kredensial sertifikat atau autentikasi Tanpa Sertifikat.

Untuk informasi selengkapnya, lihat Mulai Cepat: Mendaftarkan aplikasi.

Langkah 3: Memperbarui konfigurasi

Setelah membuat pendaftaran aplikasi, perbarui file Anda 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"]
  }
}

Aplikasi Web (MyService.Web/appsettings.json):

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "YOUR_TENANT_ID",
    "ClientId": "YOUR_WEB_CLIENT_ID",
    "CallbackPath": "/signin-oidc",
    "ClientCredentials": [
      { "SourceType": "ClientSecret" }
    ]
  },
  "WeatherApi": {
    "Scopes": ["api://YOUR_API_CLIENT_ID/.default"]
  }
}

Simpan rahasia dengan aman:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Nilai Tempat menemukan
TenantId pusat admin Microsoft Entra > Ringkasan > ID Penyewa
API ClientId Registrasi Aplikasi > MyService.ApiService > ID Aplikasi (klien)
Web ClientId Pendaftaran aplikasi > MyService.Web > ID Aplikasi (klien)
Client Secret Dibuat di Langkah 2 (salin segera setelah dibuat)

Nota

Templat pemula Aspire secara otomatis membuat kelas WeatherApiClient dalam proyek MyService.Web. HttpClient yang diketik ini digunakan di seluruh panduan ini untuk menunjukkan panggilan API yang dilindungi. Anda tidak perlu membuat kelas ini sendiri — ini adalah bagian dari templat.


Mulai segera

Bagian ini menyediakan referensi ringkas untuk menambahkan autentikasi. Untuk panduan terperinci, lihat Bagian 1 dan Bagian 2.

API (MyService.ApiService)

Instalasi paket Microsoft.Identity.Web NuGet:

dotnet add package Microsoft.Identity.Web

Tambahkan konfigurasi Microsoft Entra ke appsettings.json:

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

Daftarkan autentikasi dan otorisasi di Program.cs:

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

Aplikasi Web (MyService.Web)

Instal paket Microsoft.Identity.Web NuGet:

dotnet add package Microsoft.Identity.Web

Tambahkan konfigurasi Microsoft Entra ke 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"] }
}

Konfigurasikan autentikasi, akuisisi token, dan klien API hilir di 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();

Secara MicrosoftIdentityMessageHandler otomatis memperoleh dan melampirkan token, dan BlazorAuthenticationChallengeHandler menangani pengelolaan persetujuan dan tantangan Akses Bersyarat.

Penting

Jangan lupa untuk membuat tombol masuk UserInfo.razor. Lihat Menambahkan komponen UI Blazor untuk detailnya.

Nota

BlazorAuthenticationChallengeHandler dan LoginLogoutEndpointRouteBuilderExtensions tersedia dalam Microsoft.Identity.Web (v3.3.0+). Tidak diperlukan penyalinan file.


Mengidentifikasi file yang akan dimodifikasi

Tabel berikut mencantumkan file yang Anda ubah di setiap proyek:

Proyek File Changes
ApiService Program.cs Autentikasi Pembawa JWT, middleware otorisasi
appsettings.json konfigurasi Microsoft Entra
.csproj Tambahkan Microsoft.Identity.Web
Web Program.cs OIDC auth, akuisisi token, BlazorAuthenticationChallengeHandler
appsettings.json konfigurasi Microsoft Entra, cakupan API hilir
.csproj Tambahkan Microsoft.Identity.Web (v3.3.0+)
Components/UserInfo.razor UI tombol masuk (file baru)
Components/Layout/MainLayout.razor Sertakan komponen UserInfo
Components/Routes.razor AuthorizeRouteView untuk halaman yang dilindungi
Halaman yang memanggil API Coba/tangkap dengan ChallengeHandler

Memahami alur autentikasi

Diagram berikut menunjukkan bagaimana frontend Blazor, Microsoft Entra, dan API yang dilindungi berinteraksi:

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. Pengguna mengunjungi aplikasi Blazor → Tidak diautentikasi → melihat tombol "Masuk".
  2. Pengguna memilih Masuk → Alihkan ke /authentication/login → tantangan OIDC → Microsoft Entra.
  3. Pengguna masuk → Microsoft Entra mengalihkan ke cookie /signin-oidc → yang dibuat.
  4. Pengguna menavigasi ke halaman CuacaWeatherApiClient.GetAsync() Blazor memanggil.
  5. MicrosoftIdentityMessageHandler mencegat permintaan, memperoleh token dari cache (atau memperbarui secara diam-diam), dan melampirkan header Authorization: Bearer <token>.
  6. API menerima permintaan → Microsoft. Identity.Web memvalidasi JWT → mengembalikan data.
  7. Blazor merender data cuaca.

Tinjau struktur solusi

Templat pemula Aspire membuat tata letak proyek berikut:

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

Bagian 1: Amankan backend API dengan Microsoft. Identity.Web

Bagian ini mengonfigurasi proyek API untuk memvalidasi token Pembawa JWT yang dikeluarkan oleh Microsoft Entra.

Tambahkan paket Microsoft.Identity.Web

Jalankan perintah berikut untuk menginstal Microsoft. Paket Identity.Web NuGet:

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

Mengonfigurasi pengaturan Microsoft Entra

Tambahkan konfigurasi Microsoft Entra ke 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": "*"
}

Properti kunci:

  • ClientId: ID pendaftaran aplikasi API Microsoft Entra
  • TenantId: ID tenant Microsoft Entra Anda, atau "organizations" untuk multi-tenant, atau "common" untuk akun Microsoft
  • Audiences: Audiens token yang valid (biasanya URI ID Aplikasi Anda)

Memperbarui Program.cs API

Ganti konten MyService.ApiService/Program.cs dengan kode berikut untuk menambahkan autentikasi Pembawa JWT dan melindungi titik akhir:

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

Perubahan kunci:

  • Mendaftarkan autentikasi Pembawa JWT dengan AddMicrosoftIdentityWebApi
  • Tambahkan app.UseAuthentication() dan app.UseAuthorization() middleware
  • Terapkan .RequireAuthorization() ke titik akhir yang dilindungi

Menguji API yang dilindungi

Verifikasi bahwa API menolak permintaan yang tidak terautentikasi dan menerima token yang valid.

Kirim permintaan tanpa token:

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

Kirim permintaan dengan token yang valid:

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

Bagian 2: Mengonfigurasi frontend Blazor untuk autentikasi

Aplikasi Blazor Server menggunakan Microsoft. Identity.Web untuk:

  • Memasukkan pengguna dengan OIDC
  • Memperoleh token akses untuk memanggil API
  • Melampirkan token ke permintaan HTTP keluar

Tambahkan paket Microsoft.Identity.Web

Jalankan perintah berikut untuk menginstal Microsoft. Paket Identity.Web NuGet:

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

Konfigurasi pengaturan Microsoft Entra

Tambahkan konfigurasi Microsoft Entra dan cakupan API hilir ke 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": "*"
}

Detail konfigurasi:

  • ClientId: ID pendaftaran aplikasi web (bukan ID API)
  • ClientCredentials: Kredensial untuk aplikasi web untuk memperoleh token. Mendukung beberapa jenis kredensial. Lihat Ikhtisar Kredensial untuk opsi yang siap untuk produksi.
  • Scopes: Harus mencocokkan URI ID Aplikasi API dengan akhiran /.default

Peringatan

Untuk produksi, gunakan sertifikat atau identitas terkelola alih-alih rahasia klien. Lihat Autentikasi tanpa sertifikat untuk pendekatan yang direkomendasikan.

Perbarui Program.cs aplikasi web

Ganti konten MyService.Web/Program.cs dengan kode berikut untuk mengonfigurasi autentikasi OIDC, akuisisi token, dan klien API hilir:

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

Poin-poin penting:

  • AddMicrosoftIdentityWebApp: Mengonfigurasi autentikasi OIDC
  • EnableTokenAcquisitionToCallDownstreamApi: Mengaktifkan akuisisi token untuk API hilir
  • AddScoped<BlazorAuthenticationChallengeHandler>: Menangani persetujuan bertahap dan Akses Kondisional di Blazor Server
  • AddMicrosoftIdentityMessageHandler: Melampirkan token pembawa ke permintaan HttpClient secara otomatis
  • https+http://apiservice: Penemuan layanan Aspire memetakan ini ke URL API sebenarnya
  • Urutan middleware: UseAuthentication()UseAuthorization() titik akhir →

AddMicrosoftIdentityMessageHandler Ekstensi ini mendukung beberapa pola konfigurasi:

Opsi 1: Konfigurasi dari appsettings.json (ditunjukkan sebelumnya)

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

Opsi 2: Konfigurasi sebaris dengan Action delegate

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

Opsi 3: Konfigurasi per permintaan (tanpa parameter)

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

Menambahkan komponen UI Blazor

Penting

Langkah ini sering dilupakan. Tanpa komponen UserInfo, pengguna tidak memiliki cara untuk masuk.

BlazorAuthenticationChallengeHandler dan LoginLogoutEndpointRouteBuilderExtensions tersedia dalam Microsoft.Identity.Web v3.3.0+. Fitur-fitur ini tersedia secara otomatis setelah Anda mereferensikan paket — tidak ada penyalinan file yang diperlukan.

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

Tambahkan ke tata letak: Sertakan <UserInfo /> dalam 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>

Perbarui Routes.razor untuk AuthorizeRouteView

Ganti RouteView dengan AuthorizeRouteView di 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>

Menangani pengecualian pada HALAMAN yang memanggil API

Blazor Server memerlukan penanganan pengecualian eksplisit untuk Akses Bersyarat dan persetujuan. Anda harus menangani MicrosoftIdentityWebChallengeUserException di setiap halaman yang memanggil API hilir, kecuali aplikasi Anda diotorisasi dan Anda meminta semua cakupan sebelumnya di Program.cs.

Contoh berikut Weather.razor menunjukkan penanganan pengecualian yang tepat:

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

Polanya berfungsi sebagai berikut:

  1. IsAuthenticatedAsync() memeriksa apakah pengguna masuk sebelum melakukan panggilan API.
  2. HandleExceptionAsync() menangkap MicrosoftIdentityWebChallengeUserException (atau sebagai InnerException).
  3. Jika ini adalah pengecualian tantangan, pengguna dialihkan untuk mengautentikasi ulang dengan klaim atau cakupan yang diperlukan.
  4. Jika bukan challenge exception, HandleExceptionAsync mengembalikan false sehingga Anda dapat menangani kesalahan sendiri.

Menyimpan rahasia klien dalam rahasia pengguna

Gunakan .NET Secret Manager untuk menyimpan rahasia klien dengan aman selama pengembangan.

Perhatian

Jangan pernah menerapkan rahasia ke kontrol sumber.

Inisialisasi rahasia pengguna dan simpan rahasia klien:

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

Kemudian perbarui appsettings.json untuk menghapus rahasia yang dikodekan secara permanen:

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

Microsoft. Identity.Web mendukung beberapa jenis kredensial. Untuk produksi, lihat Ringkasan kredensial.


Memverifikasi implementasi

Gunakan daftar periksa ini untuk mengonfirmasi bahwa Anda telah menyelesaikan semua langkah yang diperlukan.

Proyek API

  • [ ] Menambahkan paket Microsoft.Identity.Web
  • [ ] Diperbarui bagian appsettings.json pada AzureAd
  • [ ] Diperbarui Program.cs dengan AddMicrosoftIdentityWebApi
  • [ ] Ditambahkan .RequireAuthorization() ke titik akhir yang dilindungi

Proyek Web/Blazor

  • [ ] Menambahkan paket Microsoft.Identity.Web (v3.3.0+)
  • [ ] Diperbarui appsettings.json ke bagian AzureAd dan WeatherApi
  • [ ] Memperbarui Program.cs melalui OIDC untuk akuisisi token
  • [ ] Ditambahkan AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Telah membuat Components/UserInfo.razor (tombol masuk)
  • [ ] Diperbarui MainLayout.razor untuk menyertakan <UserInfo />
  • [ ] Diperbarui Routes.razor dengan AuthorizeRouteView
  • [ ] Menambahkan try/catch dengan ChallengeHandler pada setiap halaman memanggil API
  • [ ] Rahasia klien tersimpan dalam rahasia pengguna

Verifikasi

  • [ ] dotnet build berhasil
  • [ ] Pendaftaran aplikasi dibuat di Pusat Admin Microsoft Entra
  • [ ] appsettings.json memiliki GUID asli (tanpa placeholder)

Menguji dan memecahkan masalah

Setelah Anda menyelesaikan implementasi, jalankan aplikasi dan verifikasi alur autentikasi end-to-end.

Jalankan aplikasi

Mulai Aspire AppHost untuk meluncurkan proyek web dan API:

# From solution root
dotnet restore
dotnet build

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

Menguji alur autentikasi

  1. Buka browser → Blazor Web UI (periksa dasbor Aspire untuk URL).
  2. Pilih Login → Masuk dengan Microsoft Entra.
  3. Navigasi ke halaman Cuaca .
  4. Verifikasi pemuatan data cuaca (dari API yang dilindungi).

Menyelesaikan masalah umum

Tabel berikut ini sering mencantumkan masalah dan solusinya:

Masalah Solusi
401 pada panggilan API Verifikasi bahwa cakupan di appsettings.json cocok dengan URI ID Aplikasi API
Pengalihan OIDC gagal Tambahkan /signin-oidc ke URI pengalihan Microsoft Entra
Token tidak terpasang Pastikan AddMicrosoftIdentityMessageHandler dipanggil pada HttpClient
Penemuan layanan gagal Periksa AppHost.cs referensi dari kedua proyek dan mereka sedang berjalan
AADSTS65001 Persetujuan admin diperlukan — memberikan persetujuan dalam pusat admin Microsoft Entra
Tidak ada tombol masuk Pastikan UserInfo.razor ada dan disertakan dalam MainLayout.razor
Perulangan persetujuan Pastikan coba/tangkap dengan HandleExceptionAsync ada di semua halaman panggilan API

Mengaktifkan pengelogan MSAL

Saat memecahkan masalah autentikasi, aktifkan pengelogan MSAL terperinci untuk melihat detail akuisisi token. Tambahkan tingkat log berikut ke appsettings.json:

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

Peringatan

Nonaktifkan pencatatan debug di produksi karena bisa terlalu rinci.

Memeriksa token

Untuk men-debug masalah token, dekodekan JWT Anda di jwt.ms dan verifikasi:

  • aud (audiens): Cocok dengan ID Klien API atau URI ID Aplikasi Anda
  • iss (penerbit): Cocok dengan penyewa Anda (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (cakupan): Memuat cakupan yang dibutuhkan
  • exp (kedaluwarsa): Token belum kedaluwarsa

Menjelajahi skenario umum

Bagian berikut menunjukkan cara memperluas implementasi dasar untuk kasus penggunaan tambahan.

Lindungi halaman Blazor

Tambahkan [Authorize] atribut ke halaman yang memerlukan autentikasi.

@page "/weather"
@attribute [Authorize]

Atau tentukan kebijakan otorisasi di Program.cs:

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

Memvalidasi cakupan dalam API

Pastikan API hanya menerima token dengan cakupan tertentu dengan menautkan RequireScope:

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

Menggunakan token khusus aplikasi (layanan ke layanan)

Untuk skenario daemon atau panggilan layanan-ke-layanan tanpa konteks pengguna, atur RequestAppToken ke 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;
});

Menggunakan kredensial tanpa sertifikat untuk produksi

Untuk penyebaran produksi di Azure, gunakan identitas terkelola alih-alih rahasia klien. Konfigurasikan bagian ClientCredentials sebagai berikut:

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

Untuk informasi selengkapnya, lihat Autentikasi tanpa sertifikat.

Memanggil API hilir dari API (atas nama)

Jika API Anda perlu memanggil API hilir lain atas nama pengguna, aktifkan akuisisi token atas nama di 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"));

Tambahkan konfigurasi API hilir ke appsettings.json:

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

Kemudian panggil API hilir dari titik akhir:

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

Untuk informasi selengkapnya, lihat Memanggil API hilir.