Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Panduan ini menunjukkan cara mengamankan aplikasi terdistribusi .NET Aspire dengan autentikasi dan otorisasi Microsoft Entra ID. Ini mencakup:
-
Frontend Blazor Server (
MyService.Web): Pengguna masuk dengan OpenID Connect dan akuisisi token -
Protected API backend (
MyService.ApiService): Validasi JWT menggunakan Microsoft. Identity.Web - 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
- .NET 9 SDK atau yang lebih baru
- .NET Aspire CLI - Lihat Instalasi Aspire CLI
- Penyewa Microsoft Entra — Lihat Daftarkan aplikasi di Microsoft Entra ID untuk penyiapan
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 dalamAudiencesdanScopes) - 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>/.defaultatauapi://<api-client-id>/access_as_user
Langkah 1: Daftarkan API
- Pergi ke pusat admin Microsoft Entra>Identity>Aplikasi>Pendaftaran aplikasi.
- Pilih Pendaftaran baru.
-
Nama:
MyService.ApiService - Jenis akun yang didukung: Akun dalam direktori organisasi ini saja (Penyewa tunggal)
- Pilih Daftarkan.
-
Nama:
- 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.
-
Nama cakupan:
- Terima default (
- Salin ID Aplikasi (klien) — Anda akan memerlukan ini untuk kedua
appsettings.jsonfile.
Untuk informasi selengkapnya, lihat Mulai Cepat: Mengonfigurasi aplikasi untuk mengekspos API web.
Langkah 2: Daftarkan aplikasi web
- 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 AndalaunchSettings.json)
- Untuk pengembangan lokal:
- Pilih Daftarkan.
-
Nama:
- Buka Autentikasi>Tambahkan URI untuk menambahkan semua URL pengembangan Anda (dari
launchSettings.json). - Buka
Sertifikat & rahasia Rahasia klien Rahasia klien baru .- Tambahkan deskripsi dan kedaluwarsa.
- Salin nilai rahasia segera — nilai tersebut tidak akan ditampilkan lagi.
- 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).
- Pilih
- 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
- Pengguna mengunjungi aplikasi Blazor → Tidak diautentikasi → melihat tombol "Masuk".
-
Pengguna memilih Masuk → Alihkan ke
/authentication/login→ tantangan OIDC → Microsoft Entra. -
Pengguna masuk → Microsoft Entra mengalihkan ke cookie
/signin-oidc→ yang dibuat. -
Pengguna menavigasi ke halaman Cuaca →
WeatherApiClient.GetAsync()Blazor memanggil. -
MicrosoftIdentityMessageHandlermencegat permintaan, memperoleh token dari cache (atau memperbarui secara diam-diam), dan melampirkan headerAuthorization: Bearer <token>. - API menerima permintaan → Microsoft. Identity.Web memvalidasi JWT → mengembalikan data.
- 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()danapp.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:
-
IsAuthenticatedAsync()memeriksa apakah pengguna masuk sebelum melakukan panggilan API. -
HandleExceptionAsync()menangkapMicrosoftIdentityWebChallengeUserException(atau sebagai InnerException). - Jika ini adalah pengecualian tantangan, pengguna dialihkan untuk mengautentikasi ulang dengan klaim atau cakupan yang diperlukan.
- Jika bukan challenge exception,
HandleExceptionAsyncmengembalikanfalsesehingga 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.jsonpadaAzureAd - [ ] Diperbarui
Program.csdenganAddMicrosoftIdentityWebApi - [ ] Ditambahkan
.RequireAuthorization()ke titik akhir yang dilindungi
Proyek Web/Blazor
- [ ] Menambahkan paket
Microsoft.Identity.Web(v3.3.0+) - [ ] Diperbarui
appsettings.jsonke bagianAzureAddanWeatherApi - [ ] Memperbarui
Program.csmelalui OIDC untuk akuisisi token - [ ] Ditambahkan
AddScoped<BlazorAuthenticationChallengeHandler>() - [ ] Telah membuat
Components/UserInfo.razor(tombol masuk) - [ ] Diperbarui
MainLayout.razoruntuk menyertakan<UserInfo /> - [ ] Diperbarui
Routes.razordenganAuthorizeRouteView - [ ] Menambahkan try/catch dengan
ChallengeHandlerpada setiap halaman memanggil API - [ ] Rahasia klien tersimpan dalam rahasia pengguna
Verifikasi
- [ ]
dotnet buildberhasil - [ ] Pendaftaran aplikasi dibuat di Pusat Admin Microsoft Entra
- [ ]
appsettings.jsonmemiliki 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
- Buka browser → Blazor Web UI (periksa dasbor Aspire untuk URL).
- Pilih Login → Masuk dengan Microsoft Entra.
- Navigasi ke halaman Cuaca .
- 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.