skenario keamanan tambahan ASP.NET Core Blazor WebAssembly
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Artikel ini menjelaskan skenario keamanan tambahan untuk Blazor WebAssembly aplikasi.
Melampirkan token ke permintaan keluar
AuthorizationMessageHandler digunakan DelegatingHandler untuk memproses token akses. Token diperoleh menggunakan IAccessTokenProvider layanan, yang didaftarkan oleh kerangka kerja. Jika token tidak dapat diperoleh, token AccessTokenNotAvailableException akan dilemparkan. AccessTokenNotAvailableException memiliki Redirect metode yang menavigasi untuk AccessTokenResult.InteractiveRequestUrl menggunakan yang diberikan AccessTokenResult.InteractionOptions untuk memungkinkan refresh token akses.
Untuk kenyamanan, kerangka kerja menyediakan BaseAddressAuthorizationMessageHandler alamat dasar aplikasi yang telah dikonfigurasi sebelumnya sebagai URL resmi. Token akses hanya ditambahkan saat URI permintaan berada dalam URI dasar aplikasi. Saat URI permintaan keluar tidak berada dalam URI dasar aplikasi, gunakan kelas kustom AuthorizationMessageHandler
(disarankan) atau konfigurasikan AuthorizationMessageHandler
.
Catatan
Selain konfigurasi aplikasi klien untuk akses API server, API server juga harus mengizinkan permintaan lintas asal (CORS) ketika klien dan server tidak berada di alamat dasar yang sama. Untuk informasi selengkapnya tentang konfigurasi CORS sisi server, lihat bagian Berbagi Sumber Daya Lintas Asal (CORS) nanti di artikel ini.
Dalam contoh berikut:
- AddHttpClientIHttpClientFactory menambahkan dan layanan terkait ke koleksi layanan dan mengonfigurasi bernama HttpClient (
WebAPI
). HttpClient.BaseAddress adalah alamat dasar URI sumber daya saat mengirim permintaan. IHttpClientFactory disediakan olehMicrosoft.Extensions.Http
paket NuGet. - BaseAddressAuthorizationMessageHandler adalah yang DelegatingHandler digunakan untuk memproses token akses. Token akses hanya ditambahkan saat URI permintaan berada dalam URI dasar aplikasi.
- IHttpClientFactory.CreateClient membuat dan mengonfigurasi instans HttpClient untuk permintaan keluar menggunakan konfigurasi yang sesuai dengan nama HttpClient (
WebAPI
).
Dalam contoh berikut, HttpClientFactoryServiceCollectionExtensions.AddHttpClient adalah ekstensi di Microsoft.Extensions.Http. Tambahkan paket ke aplikasi yang belum mereferensikannya.
Catatan
Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddHttpClient("WebAPI",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("WebAPI"));
Untuk solusi yang dihosting Blazorberdasarkan Blazor WebAssembly templat proyek, URI permintaan berada dalam URI dasar aplikasi. Oleh karena itu, IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)
) ditetapkan ke HttpClient.BaseAddress dalam aplikasi yang dihasilkan dari templat proyek.
Yang dikonfigurasi HttpClient digunakan untuk membuat permintaan resmi menggunakan try-catch
pola:
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject HttpClient Http
...
protected override async Task OnInitializedAsync()
{
try
{
var examples =
await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
Skenario permintaan autentikasi kustom
Skenario berikut menunjukkan cara menyesuaikan permintaan autentikasi dan cara mendapatkan jalur masuk dari opsi autentikasi.
Menyesuaikan proses masuk
Kelola parameter tambahan untuk permintaan masuk dengan metode berikut satu atau beberapa kali pada instans InteractiveRequestOptionsbaru :
Dalam contoh komponen berikut LoginDisplay
, parameter tambahan ditambahkan ke permintaan masuk:
prompt
diatur kelogin
: Memaksa pengguna untuk memasukkan kredensial mereka pada permintaan tersebut, menimpa akses menyeluruh.loginHint
diatur kepeter@contoso.com
: Mengisi sebelumnya bidang nama pengguna/alamat email dari halaman masuk bagi pengguna kepeter@contoso.com
. Aplikasi sering menggunakan parameter ini selama autentikasi ulang, setelah mengekstrak nama pengguna dari masuk sebelumnya menggunakanpreferred_username
klaim.
Shared/LoginDisplay.razor
:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity?.Name!
<button @onclick="BeginLogOut">Log out</button>
</Authorized>
<NotAuthorized>
<button @onclick="BeginLogIn">Log in</button>
</NotAuthorized>
</AuthorizeView>
@code{
public void BeginLogOut()
{
Navigation.NavigateToLogout("authentication/logout");
}
public void BeginLogIn()
{
InteractiveRequestOptions requestOptions =
new()
{
Interaction = InteractionType.SignIn,
ReturnUrl = Navigation.Uri,
};
requestOptions.TryAddAdditionalParameter("prompt", "login");
requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");
Navigation.NavigateToLogin("authentication/login", requestOptions);
}
}
Untuk informasi selengkapnya, lihat sumber daya berikut:
Menyesuaikan opsi sebelum mendapatkan token secara interaktif
AccessTokenNotAvailableException Jika terjadi, kelola parameter tambahan untuk permintaan token akses penyedia baru identity dengan metode berikut satu atau beberapa kali pada instans baru :InteractiveRequestOptions
Dalam contoh berikut yang mendapatkan data JSON melalui API web, parameter tambahan ditambahkan ke permintaan pengalihan jika token akses tidak tersedia (AccessTokenNotAvailableException dilemparkan):
prompt
diatur kelogin
: Memaksa pengguna untuk memasukkan kredensial mereka pada permintaan tersebut, menimpa akses menyeluruh.loginHint
diatur kepeter@contoso.com
: Mengisi sebelumnya bidang nama pengguna/alamat email dari halaman masuk bagi pengguna kepeter@contoso.com
. Aplikasi sering menggunakan parameter ini selama autentikasi ulang, setelah mengekstrak nama pengguna dari masuk sebelumnya menggunakanpreferred_username
klaim.
try
{
var examples = await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect(requestOptions => {
requestOptions.TryAddAdditionalParameter("prompt", "login");
requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");
});
}
Contoh sebelumnya mengasumsikan bahwa:
- Kehadiran
@using
/using
pernyataan untuk API di Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace layanan. HttpClient
disuntikkan sebagaiHttp
.
Untuk informasi selengkapnya, lihat sumber daya berikut:
Menyesuaikan opsi saat menggunakan IAccessTokenProvider
Jika mendapatkan token gagal saat menggunakan IAccessTokenProvider, kelola parameter tambahan untuk permintaan token akses penyedia baru identity dengan metode berikut satu atau beberapa kali pada instans InteractiveRequestOptionsbaru :
Dalam contoh berikut yang mencoba mendapatkan token akses untuk pengguna, parameter tambahan ditambahkan ke permintaan masuk jika upaya untuk mendapatkan token gagal ketika TryGetToken dipanggil:
prompt
diatur kelogin
: Memaksa pengguna untuk memasukkan kredensial mereka pada permintaan tersebut, menimpa akses menyeluruh.loginHint
diatur kepeter@contoso.com
: Mengisi sebelumnya bidang nama pengguna/alamat email dari halaman masuk bagi pengguna kepeter@contoso.com
. Aplikasi sering menggunakan parameter ini selama autentikasi ulang, setelah mengekstrak nama pengguna dari masuk sebelumnya menggunakanpreferred_username
klaim.
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { ... }
});
if (!tokenResult.TryGetToken(out var token))
{
tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint",
"peter@contoso.com");
Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl,
accessTokenResult.InteractionOptions);
}
Contoh sebelumnya mengasumsikan:
- Kehadiran
@using
/using
pernyataan untuk API di Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace layanan. - IAccessTokenProvider disuntikkan sebagai
TokenProvider
.
Untuk informasi selengkapnya, lihat sumber daya berikut:
Keluar dengan URL pengembalian kustom
Contoh berikut mengeluarkan pengguna dan mengembalikan pengguna ke /goodbye
titik akhir:
Navigation.NavigateToLogout("authentication/logout", "goodbye");
Mendapatkan jalur masuk dari opsi autentikasi
Dapatkan jalur masuk yang dikonfigurasi dari RemoteAuthenticationOptions:
var loginPath =
RemoteAuthOptions.Get(Options.DefaultName).AuthenticationPaths.LogInPath;
Contoh sebelumnya mengasumsikan:
- Kehadiran
@using
/using
pernyataan untuk API di namespace berikut: IOptionsSnapshot<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
disuntikkan sebagaiRemoteAuthOptions
.
Kelas kustom AuthorizationMessageHandler
Panduan di bagian ini direkomendasikan untuk aplikasi klien yang membuat permintaan keluar ke URI yang tidak berada dalam URI dasar aplikasi.
Dalam contoh berikut, kelas kustom diperluas AuthorizationMessageHandler untuk digunakan sebagai DelegatingHandler untuk HttpClient. ConfigureHandler mengonfigurasi handler ini untuk mengotorisasi permintaan HTTP keluar menggunakan token akses. Token akses hanya dilampirkan jika setidaknya salah satu URL yang diotorisasi adalah basis URI permintaan (HttpRequestMessage.RequestUri).
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigation)
: base(provider, navigation)
{
ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ]);
}
}
Dalam kode sebelumnya, cakupan example.read
dan example.write
merupakan contoh umum yang tidak dimaksudkan untuk mencerminkan cakupan yang valid untuk penyedia tertentu.
Program
Dalam file, CustomAuthorizationMessageHandler
terdaftar sebagai layanan sementara dan dikonfigurasi sebagai DelegatingHandler untuk instans keluar HttpResponseMessage yang dibuat oleh bernama HttpClient.
Dalam contoh berikut, HttpClientFactoryServiceCollectionExtensions.AddHttpClient adalah ekstensi di Microsoft.Extensions.Http. Tambahkan paket ke aplikasi yang belum mereferensikannya.
Catatan
Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.
builder.Services.AddTransient<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient("WebAPI",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
Catatan
Dalam contoh sebelumnya, CustomAuthorizationMessageHandler
DelegatingHandler terdaftar sebagai layanan sementara untuk AddHttpMessageHandler. Pendaftaran sementara direkomendasikan untuk IHttpClientFactory, yang mengelola cakupan DI-nya sendiri. Untuk informasi selengkapnya, lihat sumber daya berikut:
Untuk solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek, IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)
) ditetapkan ke HttpClient.BaseAddress.
Yang dikonfigurasi HttpClient digunakan untuk membuat permintaan resmi menggunakan try-catch
pola . Di mana klien dibuat dengan CreateClient (Microsoft.Extensions.Http
paket), HttpClient instans yang disediakan yang menyertakan token akses saat membuat permintaan ke API server. Jika URI permintaan adalah URI relatif, seperti dalam contoh berikut (ExampleAPIMethod
), URI permintaan dikombinasikan dengan BaseAddress saat aplikasi klien membuat permintaan:
@inject IHttpClientFactory ClientFactory
...
@code {
protected override async Task OnInitializedAsync()
{
try
{
var client = ClientFactory.CreateClient("WebAPI");
var examples =
await client.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
Mengkonfigurasi AuthorizationMessageHandler
AuthorizationMessageHandlerdapat dikonfigurasi dengan URL resmi, cakupan, dan URL pengembalian menggunakan metode .ConfigureHandler ConfigureHandler mengonfigurasi handler untuk mengotorisasi permintaan HTTP keluar menggunakan token akses. Token akses hanya dilampirkan jika setidaknya salah satu URL yang diotorisasi adalah basis URI permintaan (HttpRequestMessage.RequestUri). Jika URI permintaan adalah URI relatif, URI tersebut dikombinasikan dengan BaseAddress.
Dalam contoh berikut, AuthorizationMessageHandler mengonfigurasi HttpClient dalam Program
file:
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddScoped(sp => new HttpClient(
sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ])
.InnerHandler = new HttpClientHandler())
{
BaseAddress = new Uri("https://api.contoso.com/v1.0")
});
Dalam kode sebelumnya, cakupan example.read
dan example.write
merupakan contoh umum yang tidak dimaksudkan untuk mencerminkan cakupan yang valid untuk penyedia tertentu.
Untuk solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek, IWebAssemblyHostEnvironment.BaseAddress ditetapkan ke yang berikut ini:
- (HttpClient.BaseAddress
new Uri(builder.HostEnvironment.BaseAddress)
). - URL
authorizedUrls
array.
Diketik HttpClient
Klien yang diketik dapat didefinisikan yang menangani semua masalah akuisisi HTTP dan token dalam satu kelas.
WeatherForecastClient.cs
:
using System.Net.Http.Json;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using static {ASSEMBLY NAME}.Data;
public class WeatherForecastClient(HttpClient http)
{
private WeatherForecast[]? forecasts;
public async Task<WeatherForecast[]> GetForecastAsync()
{
try
{
forecasts = await http.GetFromJsonAsync<WeatherForecast[]>(
"WeatherForecast");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
return forecasts ?? Array.Empty<WeatherForecast>();
}
}
Dalam contoh sebelumnya, jenisnya WeatherForecast
adalah kelas statis yang menyimpan data prakiraan cuaca. Tempat {ASSEMBLY NAME}
penampung adalah nama rakitan aplikasi (misalnya, using static BlazorSample.Data;
).
Dalam contoh berikut, HttpClientFactoryServiceCollectionExtensions.AddHttpClient adalah ekstensi di Microsoft.Extensions.Http. Tambahkan paket ke aplikasi yang belum mereferensikannya.
Catatan
Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.
Dalam file Program
:
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
Untuk solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek, IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)
) ditetapkan ke HttpClient.BaseAddress.
Dalam komponen yang mengambil data cuaca:
@inject WeatherForecastClient Client
...
protected override async Task OnInitializedAsync()
{
forecasts = await Client.GetForecastAsync();
}
Mengonfigurasi handler HttpClient
Handler dapat dikonfigurasi lebih lanjut dengan ConfigureHandler untuk permintaan HTTP keluar.
Dalam contoh berikut, HttpClientFactoryServiceCollectionExtensions.AddHttpClient adalah ekstensi di Microsoft.Extensions.Http. Tambahkan paket ke aplikasi yang belum mereferensikannya.
Catatan
Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.
Dalam file Program
:
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: new [] { "https://api.contoso.com/v1.0" },
scopes: new[] { "example.read", "example.write" }));
Dalam kode sebelumnya, cakupan example.read
dan example.write
merupakan contoh umum yang tidak dimaksudkan untuk mencerminkan cakupan yang valid untuk penyedia tertentu.
Untuk solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek, IWebAssemblyHostEnvironment.BaseAddress ditetapkan ke yang berikut ini:
- (HttpClient.BaseAddress
new Uri(builder.HostEnvironment.BaseAddress)
). - URL
authorizedUrls
array.
Permintaan API web yang tidak diaauthenticated atau tidak sah di aplikasi dengan klien default yang aman
Aplikasi yang biasanya menggunakan default HttpClient aman juga dapat membuat permintaan API web yang tidak diaturentikasi atau tidak sah dengan mengonfigurasi bernama HttpClient.
Dalam contoh berikut, HttpClientFactoryServiceCollectionExtensions.AddHttpClient adalah ekstensi di Microsoft.Extensions.Http. Tambahkan paket ke aplikasi yang belum mereferensikannya.
Catatan
Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.
Dalam file Program
:
builder.Services.AddHttpClient("WebAPI.NoAuthenticationClient",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"));
Untuk solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek, IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)
) ditetapkan ke HttpClient.BaseAddress.
Pendaftaran sebelumnya adalah selain pendaftaran default HttpClient aman yang ada.
Komponen membuat HttpClient dari IHttpClientFactory (Microsoft.Extensions.Http
paket) untuk membuat permintaan yang tidak diaauthenticated atau tidak sah:
@inject IHttpClientFactory ClientFactory
...
@code {
protected override async Task OnInitializedAsync()
{
var client = ClientFactory.CreateClient("WebAPI.NoAuthenticationClient");
var examples = await client.GetFromJsonAsync<ExampleType[]>(
"ExampleNoAuthentication");
...
}
}
Catatan
Pengontrol di API server, ExampleNoAuthenticationController
untuk contoh sebelumnya, tidak ditandai dengan [Authorize]
atribut .
Keputusan apakah akan menggunakan klien yang aman atau klien yang tidak aman karena instans default HttpClient terserah pengembang. Salah satu cara untuk membuat keputusan ini adalah dengan mempertimbangkan jumlah titik akhir yang diautentikasi versus tidak diautentikasi yang dihubungi aplikasi. Jika sebagian besar permintaan aplikasi adalah mengamankan titik akhir API, gunakan instans terautentikasi HttpClient sebagai default. Jika tidak, daftarkan instans yang tidak diaauthenticated HttpClient sebagai default.
Pendekatan alternatif untuk menggunakan IHttpClientFactory adalah membuat klien yang diketik untuk akses yang tidak diaturentikasi ke titik akhir anonim.
Meminta token akses tambahan
Token akses dapat diperoleh secara manual dengan memanggil IAccessTokenProvider.RequestAccessToken. Dalam contoh berikut, cakupan tambahan diperlukan oleh aplikasi untuk default HttpClient. Contoh Microsoft Authentication Library (MSAL) mengonfigurasi cakupan dengan MsalProviderOptions
:
Dalam file Program
:
builder.Services.AddMsalAuthentication(options =>
{
...
options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 1}");
options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 2}");
}
Tempat {CUSTOM SCOPE 1}
penampung dan {CUSTOM SCOPE 2}
dalam contoh sebelumnya adalah cakupan kustom.
Catatan
AdditionalScopesToConsent tidak dapat menyediakan izin pengguna yang didelegasikan untuk Microsoft Graph melalui UI persetujuan ID Microsoft Entra saat pengguna pertama kali menggunakan aplikasi yang terdaftar di Microsoft Azure. Untuk informasi selengkapnya, lihat Menggunakan Graph API dengan ASP.NET Core Blazor WebAssembly.
Metode ini IAccessTokenProvider.RequestAccessToken menyediakan kelebihan beban yang memungkinkan aplikasi untuk menyediakan token akses dengan serangkaian cakupan tertentu.
Razor Dalam komponen:
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
...
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { "{CUSTOM SCOPE 1}", "{CUSTOM SCOPE 2}" }
});
if (tokenResult.TryGetToken(out var token))
{
...
}
Tempat {CUSTOM SCOPE 1}
penampung dan {CUSTOM SCOPE 2}
dalam contoh sebelumnya adalah cakupan kustom.
AccessTokenResult.TryGetToken menghasilkan:
true
token
dengan untuk digunakan.false
jika token tidak diambil.
Berbagi Sumber Daya Lintas Asal (CORS)
Saat mengirim kredensial (cookie/header otorisasi) pada permintaan CORS, Authorization
header harus diizinkan oleh kebijakan CORS.
Kebijakan berikut mencakup konfigurasi untuk:
- Asal permintaan (
http://localhost:5000
,https://localhost:5001
). - Metode apa pun (kata kerja).
Content-Type
danAuthorization
header. Untuk mengizinkan header kustom (misalnya,x-custom-header
), cantumkan header saat memanggil WithHeaders.- Kredensial yang diatur oleh kode JavaScript sisi klien (
credentials
properti diatur keinclude
).
app.UseCors(policy =>
policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType, HeaderNames.Authorization,
"x-custom-header")
.AllowCredentials());
Solusi yang dihosting Blazor berdasarkan Blazor WebAssembly templat proyek menggunakan alamat dasar yang sama untuk aplikasi klien dan server. Aplikasi HttpClient.BaseAddress klien diatur ke URI .builder.HostEnvironment.BaseAddress
Konfigurasi CORS tidak diperlukan dalam konfigurasi default solusi yang dihosting Blazor . Aplikasi klien tambahan yang tidak dihosting oleh proyek server dan tidak berbagi alamat dasar aplikasi server memerlukan konfigurasi CORS dalam proyek server.
Untuk informasi selengkapnya, lihat Mengaktifkan Permintaan Lintas Asal (CORS) di ASP.NET Core dan komponen Penguji Permintaan HTTP aplikasi sampel (Components/HTTPRequestTester.razor
).
Menangani kesalahan permintaan token
Ketika aplikasi satu halaman (SPA) mengautentikasi pengguna menggunakan OpenID Connect (OIDC), status autentikasi dipertahankan secara lokal dalam SPA dan di Identity Penyedia (IP) dalam bentuk sesi cookie yang ditetapkan sebagai hasil dari pengguna yang memberikan kredensial mereka.
Token yang dikeluarkan IP untuk pengguna biasanya berlaku untuk waktu yang singkat, sekitar satu jam biasanya, sehingga aplikasi klien harus secara teratur mengambil token baru. Jika tidak, pengguna akan keluar setelah token yang diberikan kedaluwarsa. Dalam kebanyakan kasus, klien OIDC dapat menyediakan token baru tanpa mengharuskan pengguna untuk mengautentikasi lagi berkat status autentikasi atau "sesi" yang disimpan dalam IP.
Ada beberapa kasus di mana klien tidak bisa mendapatkan token tanpa interaksi pengguna, misalnya, ketika karena alasan tertentu pengguna secara eksplisit keluar dari IP. Skenario ini terjadi jika pengguna mengunjungi https://login.microsoftonline.com
dan keluar. Dalam skenario ini, aplikasi tidak segera tahu bahwa pengguna telah keluar. Token apa pun yang dipegang klien mungkin tidak lagi valid. Selain itu, klien tidak dapat menyediakan token baru tanpa interaksi pengguna setelah token saat ini kedaluwarsa.
Skenario ini tidak spesifik untuk autentikasi berbasis token. Mereka adalah bagian dari sifat SPAs. SPA yang menggunakan cookie juga gagal memanggil API server jika autentikasi cookie dihapus.
Saat aplikasi melakukan panggilan API ke sumber daya yang dilindungi, Anda harus mengetahui hal-hal berikut:
- Untuk menyediakan token akses baru untuk memanggil API, pengguna mungkin diminta untuk mengautentikasi lagi.
- Bahkan jika klien memiliki token yang tampaknya valid, panggilan ke server mungkin gagal karena token dicabut oleh pengguna.
Saat aplikasi meminta token, ada dua kemungkinan hasil:
- Permintaan berhasil, dan aplikasi memiliki token yang valid.
- Permintaan gagal, dan aplikasi harus mengautentikasi pengguna lagi untuk mendapatkan token baru.
Ketika permintaan token gagal, Anda perlu memutuskan apakah Anda ingin menyimpan status saat ini sebelum melakukan pengalihan. Beberapa pendekatan ada untuk menyimpan status dengan tingkat kompleksitas yang meningkat:
- Simpan status halaman saat ini di penyimpanan sesi.
OnInitializedAsync
Selama metode siklus hidup (OnInitializedAsync), periksa apakah status dapat dipulihkan sebelum melanjutkan. - Tambahkan parameter string kueri dan gunakan sebagai cara untuk memberi sinyal aplikasi bahwa aplikasi perlu menghidrasi ulang status yang disimpan sebelumnya.
- Tambahkan parameter string kueri dengan pengidentifikasi unik untuk menyimpan data di penyimpanan sesi tanpa memperkosa tabrakan dengan item lain.
Menyimpan status aplikasi sebelum operasi autentikasi dengan penyimpanan sesi
Contoh berikut menunjukkan cara membatalkan pekerjaan.
- Pertahankan status sebelum mengalihkan ke halaman masuk.
- Pulihkan status sebelumnya setelah autentikasi menggunakan parameter string kueri.
...
@using System.Text.Json
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
@inject IJSRuntime JS
@inject NavigationManager Navigation
<EditForm Model="User" OnSubmit="OnSaveAsync">
<label>
First Name:
<InputText @bind-Value="User!.Name" />
</label>
<label>
Last Name:
<InputText @bind-Value="User!.LastName" />
</label>
<button type="submit">Save User</button>
</EditForm>
@code {
public Profile User { get; set; } = new Profile();
protected override async Task OnInitializedAsync()
{
var currentQuery = new Uri(Navigation.Uri).Query;
if (currentQuery.Contains("state=resumeSavingProfile"))
{
var user = await JS.InvokeAsync<string>("sessionStorage.getItem",
"resumeSavingProfile");
if (!string.IsNullOrEmpty(user))
{
User = JsonSerializer.Deserialize<Profile>(user);
}
}
}
public async Task OnSaveAsync()
{
var http = new HttpClient();
http.BaseAddress = new Uri(Navigation.BaseUri);
var resumeUri = Navigation.Uri + $"?state=resumeSavingProfile";
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
ReturnUrl = resumeUri
});
if (tokenResult.TryGetToken(out var token))
{
http.DefaultRequestHeaders.Add("Authorization",
$"Bearer {token.Value}");
await http.PostAsJsonAsync("Save", User);
}
else
{
await JS.InvokeVoidAsync("sessionStorage.setItem",
"resumeSavingProfile", JsonSerializer.Serialize(User));
Navigation.NavigateTo(tokenResult.InteractiveRequestUrl);
}
}
public class Profile
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
}
Menyimpan status aplikasi sebelum operasi autentikasi dengan penyimpanan sesi dan kontainer status
Selama operasi autentikasi, ada kasus di mana Anda ingin menyimpan status aplikasi sebelum browser dialihkan ke IP. Ini bisa terjadi ketika Anda menggunakan kontainer status dan ingin memulihkan status setelah autentikasi berhasil. Anda dapat menggunakan objek status autentikasi kustom untuk mempertahankan status khusus aplikasi atau referensi ke objek tersebut dan memulihkan status tersebut setelah operasi autentikasi berhasil diselesaikan. Contoh berikut menunjukkan pendekatan.
Kelas kontainer status dibuat di aplikasi dengan properti untuk menyimpan nilai status aplikasi. Dalam contoh berikut, kontainer digunakan untuk mempertahankan nilai penghitung komponen templat proyek default Blazor (Counter.razor
).Counter
Metode untuk menserialisasikan dan mendeserialisasi kontainer didasarkan pada System.Text.Json.
using System.Text.Json;
public class StateContainer
{
public int CounterValue { get; set; }
public string GetStateForLocalStorage() => JsonSerializer.Serialize(this);
public void SetStateFromLocalStorage(string locallyStoredState)
{
var deserializedState =
JsonSerializer.Deserialize<StateContainer>(locallyStoredState);
CounterValue = deserializedState.CounterValue;
}
}
Komponen Counter
menggunakan kontainer status untuk mempertahankan currentCount
nilai di luar komponen:
@page "/counter"
@inject StateContainer State
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
protected override void OnInitialized()
{
if (State.CounterValue > 0)
{
currentCount = State.CounterValue;
}
}
private void IncrementCount()
{
currentCount++;
State.CounterValue = currentCount;
}
}
ApplicationAuthenticationState
Buat dari RemoteAuthenticationState. Id
Berikan properti, yang berfungsi sebagai pengidentifikasi untuk status tersimpan secara lokal.
ApplicationAuthenticationState.cs
:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class ApplicationAuthenticationState : RemoteAuthenticationState
{
public string? Id { get; set; }
}
Komponen Authentication
(Authentication.razor
) menyimpan dan memulihkan status aplikasi menggunakan penyimpanan sesi lokal dengan StateContainer
metode serialisasi dan deserialisasi, GetStateForLocalStorage
dan SetStateFromLocalStorage
:
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IJSRuntime JS
@inject StateContainer State
<RemoteAuthenticatorViewCore Action="Action"
TAuthenticationState="ApplicationAuthenticationState"
AuthenticationState="AuthenticationState"
OnLogInSucceeded="RestoreState"
OnLogOutSucceeded="RestoreState" />
@code {
[Parameter]
public string? Action { get; set; }
public ApplicationAuthenticationState AuthenticationState { get; set; } =
new ApplicationAuthenticationState();
protected override async Task OnInitializedAsync()
{
if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn,
Action) ||
RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogOut,
Action))
{
AuthenticationState.Id = Guid.NewGuid().ToString();
await JS.InvokeVoidAsync("sessionStorage.setItem",
AuthenticationState.Id, State.GetStateForLocalStorage());
}
}
private async Task RestoreState(ApplicationAuthenticationState state)
{
if (state.Id != null)
{
var locallyStoredState = await JS.InvokeAsync<string>(
"sessionStorage.getItem", state.Id);
if (locallyStoredState != null)
{
State.SetStateFromLocalStorage(locallyStoredState);
await JS.InvokeVoidAsync("sessionStorage.removeItem", state.Id);
}
}
}
}
Contoh ini menggunakan Microsoft Entra (ME-ID) untuk autentikasi. Dalam file Program
:
- dikonfigurasi
ApplicationAuthenticationState
sebagai jenis Microsoft Authentication Library (MSAL).RemoteAuthenticationState
- Kontainer status terdaftar dalam kontainer layanan.
builder.Services.AddMsalAuthentication<ApplicationAuthenticationState>(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
builder.Services.AddSingleton<StateContainer>();
Menyesuaikan rute aplikasi
Pustaka Microsoft.AspNetCore.Components.WebAssembly.Authentication
menggunakan rute yang diperlihatkan dalam tabel berikut untuk mewakili status autentikasi yang berbeda.
Rute | Tujuan |
---|---|
authentication/login |
Memicu operasi masuk. |
authentication/login-callback |
Menangani hasil operasi masuk apa pun. |
authentication/login-failed |
Menampilkan pesan kesalahan ketika operasi masuk gagal karena beberapa alasan. |
authentication/logout |
Memicu operasi keluar. |
authentication/logout-callback |
Menangani hasil operasi keluar. |
authentication/logout-failed |
Menampilkan pesan kesalahan ketika operasi keluar gagal karena beberapa alasan. |
authentication/logged-out |
Menunjukkan bahwa pengguna telah berhasil keluar. |
authentication/profile |
Memicu operasi untuk mengedit profil pengguna. |
authentication/register |
Memicu operasi untuk mendaftarkan pengguna baru. |
Rute yang ditampilkan dalam tabel sebelumnya dapat dikonfigurasi melalui RemoteAuthenticationOptions<TRemoteAuthenticationProviderOptions>.AuthenticationPaths. Saat mengatur opsi untuk menyediakan rute kustom, konfirmasikan bahwa aplikasi memiliki rute yang menangani setiap jalur.
Dalam contoh berikut, semua jalur diawali dengan /security
.
Authentication
komponen (Authentication.razor
):
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code{
[Parameter]
public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code{
[Parameter]
public string Action { get; set; }
}
Dalam file Program
:
builder.Services.AddApiAuthorization(options => {
options.AuthenticationPaths.LogInPath = "security/login";
options.AuthenticationPaths.LogInCallbackPath = "security/login-callback";
options.AuthenticationPaths.LogInFailedPath = "security/login-failed";
options.AuthenticationPaths.LogOutPath = "security/logout";
options.AuthenticationPaths.LogOutCallbackPath = "security/logout-callback";
options.AuthenticationPaths.LogOutFailedPath = "security/logout-failed";
options.AuthenticationPaths.LogOutSucceededPath = "security/logged-out";
options.AuthenticationPaths.ProfilePath = "security/profile";
options.AuthenticationPaths.RegisterPath = "security/register";
});
Jika persyaratan memanggil jalur yang sama sekali berbeda, atur rute seperti yang dijelaskan sebelumnya dan render RemoteAuthenticatorView dengan parameter tindakan eksplisit:
@page "/register"
<RemoteAuthenticatorView Action="RemoteAuthenticationActions.Register" />
Anda diizinkan untuk memecah UI ke halaman yang berbeda jika Anda memilih untuk melakukannya.
Menyesuaikan antarmuka pengguna autentikasi
RemoteAuthenticatorView menyertakan sekumpulan fragmen UI default untuk setiap status autentikasi. Setiap status dapat disesuaikan dengan meneruskan kustom RenderFragment. Untuk menyesuaikan teks yang ditampilkan selama proses masuk awal, dapat mengubah RemoteAuthenticatorView sebagai berikut.
Authentication
komponen (Authentication.razor
):
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string Action { get; set; }
}
RemoteAuthenticatorView memiliki satu fragmen yang dapat digunakan per rute autentikasi yang diperlihatkan dalam tabel berikut.
Rute | Fragmen |
---|---|
authentication/login |
<LoggingIn> |
authentication/login-callback |
<CompletingLoggingIn> |
authentication/login-failed |
<LogInFailed> |
authentication/logout |
<LogOut> |
authentication/logout-callback |
<CompletingLogOut> |
authentication/logout-failed |
<LogOutFailed> |
authentication/logged-out |
<LogOutSucceeded> |
authentication/profile |
<UserProfile> |
authentication/register |
<Registering> |
Mengkustomisasi pengguna
Pengguna yang terikat ke aplikasi dapat disesuaikan.
Menyesuaikan pengguna dengan klaim payload
Dalam contoh berikut, pengguna terautentikasi aplikasi menerima amr
klaim untuk setiap metode autentikasi pengguna. Klaim amr
mengidentifikasi bagaimana subjek token diautentikasi dalam klaim payload platform Microsoft identity v1.0. Contohnya menggunakan kelas akun pengguna kustom berdasarkan RemoteUserAccount.
Buat kelas yang memperluas RemoteUserAccount kelas. Contoh berikut mengatur AuthenticationMethod
properti ke array amr
nilai properti JSON pengguna. AuthenticationMethod
diisi secara otomatis oleh kerangka kerja saat pengguna diautentikasi.
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("amr")]
public string[]? AuthenticationMethod { get; set; }
}
Buat pabrik yang diperluas AccountClaimsPrincipalFactory<TAccount> untuk membuat klaim dari metode autentikasi pengguna yang disimpan di CustomUserAccount.AuthenticationMethod
:
using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomAccountFactory(NavigationManager navigation,
IAccessTokenProviderAccessor accessor)
: AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account, RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity != null && initialUser.Identity.IsAuthenticated)
{
var userIdentity = (ClaimsIdentity)initialUser.Identity;
if (account.AuthenticationMethod is not null)
{
foreach (var value in account.AuthenticationMethod)
{
userIdentity.AddClaim(new Claim("amr", value));
}
}
}
return initialUser;
}
}
Daftarkan CustomAccountFactory
untuk penyedia autentikasi yang digunakan. Salah satu pendaftaran berikut ini valid:
-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddOidcAuthentication<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>();
-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>();
-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddApiAuthorization<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>();
Grup dan peran keamanan ME-ID dengan kelas akun pengguna kustom
Untuk contoh tambahan yang berfungsi dengan grup keamanan ME-ID dan Peran Administrator ME-ID dan kelas akun pengguna kustom, lihat ASP.NET Core Blazor WebAssembly dengan grup dan peran ID Microsoft Entra.
Pra-penyajian dengan autentikasi
Konten pra-penyajian yang memerlukan autentikasi dan otorisasi saat ini tidak didukung. Setelah mengikuti panduan di salah Blazor WebAssembly satu topik aplikasi keamanan, gunakan instruksi berikut untuk membuat aplikasi yang:
- Jalur prarender yang otorisasinya tidak diperlukan.
- Tidak merender jalur yang otorisasinya diperlukan.
Client Untuk file proyekProgram
, faktor pendaftaran layanan umum ke dalam metode terpisah (misalnya, buat ConfigureCommonServices
metode dalam Client proyek). Layanan umum adalah layanan yang didaftarkan pengembang untuk digunakan oleh proyek klien dan server.
public static void ConfigureCommonServices(IServiceCollection services)
{
services.Add...;
}
Dalam file Program
:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.Services.AddScoped( ... );
ConfigureCommonServices(builder.Services);
await builder.Build().RunAsync();
Server Dalam file proyekProgram
, daftarkan layanan tambahan berikut dan panggil ConfigureCommonServices
:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddRazorPages();
builder.Services.TryAddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
Client.Program.ConfigureCommonServices(services);
Server Dalam metode proyekStartup.ConfigureServices
, daftarkan layanan tambahan berikut dan panggil ConfigureCommonServices
:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public void ConfigureServices(IServiceCollection services)
{
...
services.AddRazorPages();
services.AddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
services.AddScoped<SignOutSessionStateManager>();
Client.Program.ConfigureCommonServices(services);
}
Untuk informasi selengkapnya tentang Blazor penyedia autentikasi server kerangka kerja (ServerAuthenticationStateProvider
), lihat autentikasi dan otorisasi inti Blazor ASP.NET.
Server Dalam file proyekPages/_Host.cshtml
, ganti Pembantu Component
Tag (<component ... />
) dengan yang berikut ini:
<div id="app">
@if (HttpContext.Request.Path.StartsWithSegments("/authentication"))
{
<component type="typeof({CLIENT APP ASSEMBLY NAME}.App)"
render-mode="WebAssembly" />
}
else
{
<component type="typeof({CLIENT APP ASSEMBLY NAME}.App)"
render-mode="WebAssemblyPrerendered" />
}
</div>
Dalam contoh sebelumnya:
- Tempat
{CLIENT APP ASSEMBLY NAME}
penampung adalah nama rakitan aplikasi klien (misalnyaBlazorSample.Client
). - Pemeriksaan kondisi untuk
/authentication
segmen jalur:- Menghindari pra-penyajian (
render-mode="WebAssembly"
) untuk jalur autentikasi. - Prarender (
render-mode="WebAssemblyPrerendered"
) untuk jalur non-autentikasi.
- Menghindari pra-penyajian (
Opsi untuk aplikasi yang dihosting dan penyedia login pihak ketiga
Saat mengautentikasi dan mengotorisasi aplikasi yang dihosting Blazor WebAssembly dengan penyedia pihak ketiga, ada beberapa opsi yang tersedia untuk mengautentikasi pengguna. Mana yang Anda pilih tergantung pada skenario Anda.
Untuk informasi lebih lanjut, lihat Menyimpan klaim dan token tambahan dari penyedia eksternal di ASP.NET Core.
Mengautentikasi pengguna untuk hanya memanggil API pihak ketiga yang dilindungi
Autentikasi pengguna dengan alur OAuth sisi klien terhadap penyedia API pihak ketiga:
builder.services.AddOidcAuthentication(options => { ... });
Dalam skenario ini:
- Server yang menghosting aplikasi tidak memainkan peran.
- API di server tidak dapat dilindungi.
- Aplikasi ini hanya dapat memanggil API pihak ketiga yang dilindungi.
Mengautentikasi pengguna dengan penyedia pihak ketiga dan memanggil API yang dilindungi di server host dan pihak ketiga
Konfigurasikan Identity dengan penyedia login pihak ketiga. Dapatkan token yang diperlukan untuk akses API pihak ketiga dan simpan.
Saat pengguna masuk, Identity mengumpulkan token akses dan refresh sebagai bagian dari proses autentikasi. Pada saat itu, ada beberapa pendekatan yang tersedia untuk melakukan panggilan API ke API pihak ketiga.
Menggunakan token akses server untuk mengambil token akses pihak ketiga
Gunakan token akses yang dihasilkan di server untuk mengambil token akses pihak ketiga dari titik akhir API server. Dari sana, gunakan token akses pihak ketiga untuk memanggil sumber daya API pihak ketiga langsung dari Identity klien.
Kami tidak merekomendasikan pendekatan ini. Pendekatan ini mengharuskan memperlakukan token akses pihak ketiga seolah-olah dibuat untuk klien publik. Dalam istilah OAuth, aplikasi publik tidak memiliki rahasia klien karena tidak dapat dipercaya untuk menyimpan rahasia dengan aman, dan token akses diproduksi untuk klien rahasia. Klien rahasia adalah klien yang memiliki rahasia klien dan diasumsikan dapat menyimpan rahasia dengan aman.
- Token akses pihak ketiga mungkin diberikan cakupan tambahan untuk melakukan operasi sensitif berdasarkan fakta bahwa pihak ketiga memancarkan token untuk klien yang lebih tepercaya.
- Demikian pula, token refresh tidak boleh dikeluarkan untuk klien yang tidak tepercaya, karena melakukannya memberi klien akses tak terbatas kecuali pembatasan lain diberlakukan.
Lakukan panggilan API dari klien ke API server untuk memanggil API pihak ketiga
Lakukan panggilan API dari klien ke API server. Dari server, ambil token akses untuk sumber daya API pihak ketiga dan terbitkan panggilan apa pun yang diperlukan.
Kami merekomendasikan pendekatan ini. Meskipun pendekatan ini memerlukan hop jaringan tambahan melalui server untuk memanggil API pihak ketiga, pendekatan ini pada akhirnya menghasilkan pengalaman yang lebih aman:
- Server dapat menyimpan token refresh dan memastikan bahwa aplikasi tidak kehilangan akses ke sumber daya pihak ketiga.
- Aplikasi tidak dapat membocorkan token akses dari server yang mungkin berisi izin yang lebih sensitif.
Menggunakan titik akhir OpenID Connect (OIDC) v2.0
Pustaka autentikasi dan Blazor templat proyek menggunakan titik akhir OpenID Connect (OIDC) v1.0. Untuk menggunakan titik akhir v2.0, konfigurasikan opsi Pembawa JwtBearerOptions.Authority JWT. Dalam contoh berikut, ME-ID dikonfigurasi untuk v2.0 dengan menambahkan v2.0
segmen ke Authority properti :
using Microsoft.AspNetCore.Authentication.JwtBearer;
...
builder.Services.Configure<JwtBearerOptions>(
JwtBearerDefaults.AuthenticationScheme,
options =>
{
options.Authority += "/v2.0";
});
Atau, pengaturan dapat dibuat dalam file pengaturan aplikasi (appsettings.json
):
{
"Local": {
"Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/",
...
}
}
Jika tacking pada segmen ke otoritas tidak sesuai untuk penyedia OIDC aplikasi, seperti dengan penyedia non-ME-ID, atur properti secara Authority langsung. Atur properti di atau JwtBearerOptions di file pengaturan aplikasi (appsettings.json
) dengan Authority
kunci .
Daftar klaim dalam token ID berubah untuk titik akhir v2.0. Dokumentasi Microsoft tentang perubahan telah dihentikan, tetapi panduan tentang klaim dalam token ID tersedia dalam referensi klaim token ID.
Mengonfigurasi dan menggunakan gRPC dalam komponen
Untuk mengonfigurasi Blazor WebAssembly aplikasi untuk menggunakan kerangka kerja ASP.NET Core gRPC:
- Aktifkan gRPC-Web di server. Untuk informasi selengkapnya, lihat gRPC-Web di aplikasi gRPC ASP.NET Core.
- Daftarkan layanan gRPC untuk penanganan pesan aplikasi. Contoh berikut mengonfigurasi handler pesan otorisasi aplikasi untuk menggunakan
GreeterClient
layanan dari tutorial gRPC (Program
file).
Catatan
Pra-penyajian diaktifkan secara default, Blazor Web Appjadi Anda harus memperhitungkan rendering komponen terlebih dahulu dari server lalu dari klien. Status yang telah dirender harus mengalir ke klien sehingga dapat digunakan kembali. Untuk informasi selengkapnya, lihat Prarender komponen ASP.NET CoreRazor.
Catatan
Pra-penyajian diaktifkan secara default di aplikasi yang dihosting, jadi Anda harus memperhitungkan Blazor WebAssembly penyajian komponen terlebih dahulu dari server lalu dari klien. Status yang telah dirender harus mengalir ke klien sehingga dapat digunakan kembali. Untuk informasi selengkapnya, lihat Mengintegrasikan komponen ASP.NET CoreRazor.
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
...
builder.Services.AddScoped(sp =>
{
var baseAddressMessageHandler =
sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>();
baseAddressMessageHandler.InnerHandler = new HttpClientHandler();
var grpcWebHandler =
new GrpcWebHandler(GrpcWebMode.GrpcWeb, baseAddressMessageHandler);
var channel = GrpcChannel.ForAddress(builder.HostEnvironment.BaseAddress,
new GrpcChannelOptions { HttpHandler = grpcWebHandler });
return new Greeter.GreeterClient(channel);
});
Komponen dalam aplikasi klien dapat melakukan panggilan gRPC menggunakan klien gRPC (Grpc.razor
):
@page "/grpc"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject Greeter.GreeterClient GreeterClient
<h1>Invoke gRPC service</h1>
<p>
<input @bind="name" placeholder="Type your name" />
<button @onclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>
Server response: <strong>@serverResponse</strong>
@code {
private string name = "Bert";
private string? serverResponse;
private async Task GetGreeting()
{
try
{
var request = new HelloRequest { Name = name };
var reply = await GreeterClient.SayHelloAsync(request);
serverResponse = reply.Message;
}
catch (Grpc.Core.RpcException ex)
when (ex.Status.DebugException is
AccessTokenNotAvailableException tokenEx)
{
tokenEx.Redirect();
}
}
}
Untuk menggunakan Status.DebugException
properti , gunakan Grpc.Net.Client
versi 2.30.0 atau yang lebih baru.
Untuk informasi selengkapnya, lihat gRPC-Web di aplikasi gRPC ASP.NET Core.
AuthenticationService
Ganti implementasi
Sub bagian berikut menjelaskan cara mengganti:
- Implementasi JavaScript
AuthenticationService
apa pun. - Pustaka Autentikasi Microsoft untuk JavaScript (
MSAL.js
).
Ganti implementasi JavaScript AuthenticationService
apa pun
Buat pustaka JavaScript untuk menangani detail autentikasi kustom Anda.
Peringatan
Panduan di bagian ini adalah detail implementasi dari default RemoteAuthenticationService<TRemoteAuthenticationState,TAccount,TProviderOptions>. Kode TypeScript di bagian ini berlaku khusus untuk ASP.NET Core di .NET 7 dan dapat berubah tanpa pemberitahuan dalam rilis ASP.NET Core mendatang.
// .NET makes calls to an AuthenticationService object in the Window.
declare global {
interface Window { AuthenticationService: AuthenticationService }
}
export interface AuthenticationService {
// Init is called to initialize the AuthenticationService.
public static init(settings: UserManagerSettings & AuthorizeServiceSettings, logger: any) : Promise<void>;
// Gets the currently authenticated user.
public static getUser() : Promise<{[key: string] : string }>;
// Tries to get an access token silently.
public static getAccessToken(options: AccessTokenRequestOptions) : Promise<AccessTokenResult>;
// Tries to sign in the user or get an access token interactively.
public static signIn(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the sign-in process when a redirect is used.
public static async completeSignIn(url: string) : Promise<AuthenticationResult>;
// Signs the user out.
public static signOut(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the signout callback when a redirect is used.
public static async completeSignOut(url: string) : Promise<AuthenticationResult>;
}
// The rest of these interfaces match their C# definitions.
export interface AccessTokenRequestOptions {
scopes: string[];
returnUrl: string;
}
export interface AccessTokenResult {
status: AccessTokenResultStatus;
token?: AccessToken;
}
export interface AccessToken {
value: string;
expires: Date;
grantedScopes: string[];
}
export enum AccessTokenResultStatus {
Success = 'Success',
RequiresRedirect = 'RequiresRedirect'
}
export enum AuthenticationResultStatus {
Redirect = 'Redirect',
Success = 'Success',
Failure = 'Failure',
OperationCompleted = 'OperationCompleted'
};
export interface AuthenticationResult {
status: AuthenticationResultStatus;
state?: unknown;
message?: string;
}
export interface AuthenticationContext {
state?: unknown;
interactiveRequest: InteractiveAuthenticationRequest;
}
export interface InteractiveAuthenticationRequest {
scopes?: string[];
additionalRequestParameters?: { [key: string]: any };
};
Anda dapat mengimpor pustaka dengan menghapus tag asli <script>
dan menambahkan <script>
tag yang memuat pustaka kustom. Contoh berikut menunjukkan penggantian tag default <script>
dengan yang memuat pustaka bernama CustomAuthenticationService.js
dari wwwroot/js
folder.
Di wwwroot/index.html
sebelum skrip (_framework/blazor.webassembly.js
) di dalam tag penutup </body>
Blazor:
- <script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
+ <script src="js/CustomAuthenticationService.js"></script>
Untuk informasi selengkapnya, lihat AuthenticationService.ts
di dotnet/aspnetcore
repositori GitHub.
Catatan
Tautan dokumentasi ke sumber referensi .NET biasanya memuat cabang default repositori, yang mewakili pengembangan saat ini untuk rilis .NET berikutnya. Untuk memilih tag rilis tertentu, gunakan daftar dropdown Beralih cabang atau tag. Untuk informasi lebih lanjut, lihat Cara memilih tag versi kode sumber ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Ganti Pustaka Autentikasi Microsoft untuk JavaScript (MSAL.js
)
Jika aplikasi memerlukan versi kustom Pustaka Autentikasi Microsoft untuk JavaScript (MSAL.js
), lakukan langkah-langkah berikut:
- Konfirmasikan sistem memiliki pengembang terbaru .NET SDK atau dapatkan dan instal SDK pengembang terbaru dari .NET Core SDK: Penginstal dan Biner. Konfigurasi umpan NuGet internal tidak diperlukan untuk skenario ini.
- Siapkan
dotnet/aspnetcore
repositori GitHub untuk pengembangan setelah dokumentasi di Build ASP.NET Core dari Sumber. Fork dan kloning atau unduh arsip ZIP repositoridotnet/aspnetcore
GitHub. src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json
Buka file dan atur versi yang diinginkan dari@azure/msal-browser
. Untuk daftar versi yang dirilis, kunjungi@azure/msal-browser
situs web npm dan pilih tab Versi .Authentication.Msal
Buat proyek disrc/Components/WebAssembly/Authentication.Msal/src
folder denganyarn build
perintah dalam shell perintah.- Jika aplikasi menggunakan aset terkompresi (Brotli/Gzip), kompres
Interop/dist/Release/AuthenticationService.js
file. AuthenticationService.js
Salin file dan versi terkompresi (.br
/.gz
) file, jika diproduksi, dariInterop/dist/Release
folder ke folder aplikasipublish/wwwroot/_content/Microsoft.Authentication.WebAssembly.Msal
di aset yang diterbitkan aplikasi.
Meneruskan opsi penyedia kustom
Tentukan kelas untuk meneruskan data ke pustaka JavaScript yang mendasar.
Penting
Struktur kelas harus sesuai dengan apa yang diharapkan pustaka ketika JSON diserialisasikan dengan System.Text.Json.
Contoh berikut menunjukkan kelas dengan atribut yang ProviderOptions
cocok dengan JsonPropertyName
harapan pustaka penyedia kustom hipotetis:
public class ProviderOptions
{
public string? Authority { get; set; }
public string? MetadataUrl { get; set; }
[JsonPropertyName("client_id")]
public string? ClientId { get; set; }
public IList<string> DefaultScopes { get; set; } = [ "openid", "profile" ];
[JsonPropertyName("redirect_uri")]
public string? RedirectUri { get; set; }
[JsonPropertyName("post_logout_redirect_uri")]
public string? PostLogoutRedirectUri { get; set; }
[JsonPropertyName("response_type")]
public string? ResponseType { get; set; }
[JsonPropertyName("response_mode")]
public string? ResponseMode { get; set; }
}
Daftarkan opsi penyedia dalam sistem DI dan konfigurasikan nilai yang sesuai:
builder.Services.AddRemoteAuthentication<RemoteAuthenticationState, RemoteUserAccount,
ProviderOptions>(options => {
options.ProviderOptions.Authority = "...";
options.ProviderOptions.MetadataUrl = "...";
options.ProviderOptions.ClientId = "...";
options.ProviderOptions.DefaultScopes = [ "openid", "profile", "myApi" ];
options.ProviderOptions.RedirectUri = "https://localhost:5001/authentication/login-callback";
options.ProviderOptions.PostLogoutRedirectUri = "https://localhost:5001/authentication/logout-callback";
options.ProviderOptions.ResponseType = "...";
options.ProviderOptions.ResponseMode = "...";
});
Contoh sebelumnya menetapkan URI pengalihan dengan literal string reguler. Alternatif berikut tersedia:
TryCreate menggunakan IWebAssemblyHostEnvironment.BaseAddress:
Uri.TryCreate( $"{builder.HostEnvironment.BaseAddress}authentication/login-callback", UriKind.Absolute, out var redirectUri); options.RedirectUri = redirectUri;
Konfigurasi penyusun host:
options.RedirectUri = builder.Configuration["RedirectUri"];
wwwroot/appsettings.json
:{ "RedirectUri": "https://localhost:5001/authentication/login-callback" }
Sumber Daya Tambahan:
ASP.NET Core