Bagikan melalui


Mengamankan ASP.NET Core Blazor WebAssembly dengan ASP.NET Core Identity

Aplikasi mandiri Blazor WebAssembly dapat diamankan dengan ASP.NET Core Identity dengan mengikuti panduan dalam artikel ini.

Titik akhir untuk mendaftar, masuk, dan keluar

Alih-alih menggunakan UI default yang disediakan oleh ASP.NET Core Identity untuk SPA dan Blazor aplikasi, yang didasarkan pada Razor Pages, panggil MapIdentityApi DI API backend untuk menambahkan JStitik akhir ON API untuk mendaftar dan masuk ke pengguna dengan ASP.NET Core Identity. Identity Titik akhir API juga mendukung fitur lanjutan, seperti autentikasi dua faktor dan verifikasi email.

Pada klien, panggil /register titik akhir untuk mendaftarkan pengguna dengan alamat email dan kata sandi mereka:

var result = await _httpClient.PostAsJsonAsync(
    "register", new
    {
        email,
        password
    });

Pada klien, masuk ke pengguna dengan cookie autentikasi menggunakan /login titik akhir dengan useCookies string kueri diatur ke true:

var result = await _httpClient.PostAsJsonAsync(
    "login?useCookies=true", new
    {
        email,
        password
    });

API server backend menetapkan cookie autentikasi dengan panggilan ke AddIdentityCookies pada penyusun autentikasi:

builder.Services
    .AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddIdentityCookies();

Autentikasi token

Untuk skenario asli dan seluler di mana beberapa klien tidak mendukung cookie, API login menyediakan parameter untuk meminta token. Token kustom (yang merupakan milik platform ASP.NET Core Identity ) dikeluarkan yang dapat digunakan untuk mengautentikasi permintaan berikutnya. Token harus diteruskan di Authorization header sebagai token pembawa. Token refresh juga disediakan. Token ini memungkinkan aplikasi untuk meminta token baru ketika yang lama kedaluwarsa tanpa memaksa pengguna untuk masuk lagi.

Token bukan on Web Token standar JS(JWT). Penggunaan token kustom disengaja, karena API bawaan Identity dimaksudkan terutama untuk skenario sederhana. Opsi token tidak dimaksudkan untuk menjadi penyedia layanan identitas atau server token berfitur lengkap, tetapi sebagai alternatif untuk cookie opsi untuk klien yang tidak dapat menggunakannya cookie.

Panduan berikut memulai proses penerapan autentikasi berbasis token dengan API login. Kode kustom diperlukan untuk menyelesaikan implementasi. Untuk informasi selengkapnya, lihat Menggunakan Identity untuk mengamankan backend API Web untuk SPAs.

Alih-alih API server backend yang membuat cookie autentikasi dengan panggilan ke AddIdentityCookies pada pembuat autentikasi, API server menyiapkan autentikasi token pembawa dengan AddBearerToken metode ekstensi. Tentukan skema untuk token autentikasi pembawa dengan IdentityConstants.BearerScheme.

Di Backend/Program.cs, ubah layanan dan konfigurasi autentikasi menjadi yang berikut ini:

builder.Services
    .AddAuthentication()
    .AddBearerToken(IdentityConstants.BearerScheme);

Di BlazorWasmAuth/Identity/CookieAuthenticationStateProvider.cs, hapus useCookies parameter string kueri dalam LoginAsync metode CookieAuthenticationStateProvider:

- login?useCookies=true
+ login

Pada titik ini, Anda harus menyediakan kode kustom untuk mengurai AccessTokenResponse pada klien dan mengelola token akses dan refresh. Untuk informasi selengkapnya, lihat Menggunakan Identity untuk mengamankan backend API Web untuk SPAs.

Skenario tambahan Identity

Untuk skenario tambahan Identity yang disediakan oleh API, lihat Menggunakan Identity untuk mengamankan backend API Web untuk SPAs:

  • Mengamankan titik akhir yang dipilih
  • Autentikasi token
  • Autentikasi dua faktor (2FA)
  • Kode pemulihan
  • Manajemen info pengguna

Aplikasi sampel

Dalam artikel ini, aplikasi sampel berfungsi sebagai referensi untuk aplikasi mandiri Blazor WebAssembly yang mengakses ASP.NET Core Identity melalui API web backend. Demonstrasi ini mencakup dua aplikasi:

  • Backend: Aplikasi API web backend yang mempertahankan penyimpanan identitas pengguna untuk ASP.NET Core Identity.
  • BlazorWasmAuth: Aplikasi frontend mandiri Blazor WebAssembly dengan autentikasi pengguna.

Akses aplikasi sampel melalui folder versi terbaru dari akar repositori dengan tautan berikut. Sampel disediakan untuk .NET 8 atau yang lebih baru. README Lihat file di BlazorWebAssemblyStandaloneWithIdentity folder untuk langkah-langkah tentang cara menjalankan aplikasi sampel.

Melihat atau mengunduh kode sampel (cara mengunduh)

Paket dan kode aplikasi API web backend

Aplikasi API web backend mempertahankan penyimpanan identitas pengguna untuk ASP.NET Core Identity.

Paket

Aplikasi ini menggunakan paket NuGet berikut:

Jika aplikasi Anda menggunakan penyedia database yang berbeda EF Core dari penyedia dalam memori, jangan buat referensi paket di aplikasi Anda untuk Microsoft.EntityFrameworkCore.InMemory.

Dalam file proyek aplikasi (.csproj), globalisasi invarian dikonfigurasi.

Contoh kode aplikasi

Pengaturan aplikasi mengonfigurasi URL backend dan frontend:

  • Backend app (BackendUrl): https://localhost:7211
  • BlazorWasmAuth app (FrontendUrl): https://localhost:7171

File Backend.http dapat digunakan untuk menguji permintaan data cuaca. Perhatikan bahwa BlazorWasmAuth aplikasi harus berjalan untuk menguji titik akhir, dan titik akhir dikodekan secara permanen ke dalam file. Untuk informasi selengkapnya, lihat Menggunakan file .http di Visual Studio 2022.

Penyiapan dan konfigurasi berikut ditemukan dalam file aplikasiProgram.

Identitas pengguna dengan cookie autentikasi ditambahkan dengan memanggil AddAuthentication dan AddIdentityCookies. Layanan untuk pemeriksaan otorisasi ditambahkan oleh panggilan ke AddAuthorizationBuilder.

Hanya direkomendasikan untuk demonstrasi, aplikasi menggunakan EF Core penyedia database dalam memori untuk pendaftaran konteks database (AddDbContext). Penyedia database dalam memori memudahkan untuk menghidupkan ulang aplikasi dan menguji alur pengguna pendaftaran dan login. Setiap eksekusi dimulai dengan database baru, tetapi aplikasi menyertakan kode demonstrasi seeding pengguna uji, yang dijelaskan nanti dalam artikel ini. Jika database diubah menjadi SQLite, pengguna disimpan di antara sesi, tetapi database harus dibuat melalui migrasi, seperti yang EF Core ditunjukkan dalam tutorial memulai. Anda dapat menggunakan penyedia relasional lain seperti SQL Server untuk kode produksi Anda.

Konfigurasikan Identity untuk menggunakan EF Core database dan mengekspos Identity titik akhir melalui panggilan ke AddIdentityCore, AddEntityFrameworkStores, dan AddApiEndpoints.

Kebijakan Berbagi Sumber Daya Lintas Asal (CORS) dibuat untuk mengizinkan permintaan dari aplikasi frontend dan backend. URL fallback dikonfigurasi untuk kebijakan CORS jika pengaturan aplikasi tidak menyediakannya:

  • Backend app (BackendUrl): https://localhost:5001
  • BlazorWasmAuth app (FrontendUrl): https://localhost:5002

Layanan dan titik akhir untuk Swagger/OpenAPI disertakan untuk dokumentasi API web dan pengujian pengembangan. Untuk informasi selengkapnya tentang NSwag, lihat Mulai menggunakan NSwag dan ASP.NET Core.

Klaim peran pengguna dikirim dari API Minimal di /roles titik akhir.

Rute dipetakan untuk Identity titik akhir dengan memanggil MapIdentityApi<AppUser>().

Titik akhir keluar (/Logout) dikonfigurasi dalam alur middleware untuk mengeluarkan pengguna.

Untuk mengamankan titik akhir, tambahkan RequireAuthorization metode ekstensi ke definisi rute. Untuk pengontrol, tambahkan [Authorize] atribut ke pengontrol atau tindakan.

Untuk informasi selengkapnya tentang pola dasar untuk inisialisasi dan konfigurasi DbContext instans, lihat DbContext Lifetime, Configuration, dan Initialization dalam EF Core dokumentasi.

Paket dan kode aplikasi mandiri Blazor WebAssembly frontend

Aplikasi frontend mandiri Blazor WebAssembly menunjukkan autentikasi dan otorisasi pengguna untuk mengakses halaman web privat.

Paket

Aplikasi ini menggunakan paket NuGet berikut:

Contoh kode aplikasi

Folder Models berisi model aplikasi:

Antarmuka IAccountManagement (Identity/CookieHandler.cs) menyediakan layanan manajemen akun.

Kelas CookieAuthenticationStateProvider (Identity/CookieAuthenticationStateProvider.cs) menangani status untuk cookieautentikasi berbasis dan menyediakan implementasi layanan manajemen akun yang dijelaskan oleh IAccountManagement antarmuka. Metode ini LoginAsync secara eksplisit memungkinkan cookie autentikasi melalui useCookies nilai string kueri .true Kelas ini juga mengelola pembuatan klaim peran untuk pengguna yang diautentikasi.

Kelas CookieHandler (Identity/CookieHandler.cs) memastikan cookie kredensial dikirim dengan setiap permintaan ke API web backend, yang menangani Identity dan memelihara penyimpanan Identity data.

menyediakan wwwroot/appsettings.file titik akhir URL ujung belakang dan ujung depan.

Komponen App mengekspos status autentikasi sebagai parameter kaskading. Untuk informasi selengkapnya, lihat autentikasi dan otorisasi ASP.NET CoreBlazor.

Komponen MainLayout dan NavMenu komponen menggunakan AuthorizeView komponen untuk menampilkan konten secara selektif berdasarkan status autentikasi pengguna.

Komponen berikut menangani tugas autentikasi pengguna umum, memanfaatkan IAccountManagement layanan:

Komponen PrivatePage (Components/Pages/PrivatePage.razor) memerlukan autentikasi dan menunjukkan klaim pengguna.

Layanan dan konfigurasi disediakan dalam Program file (Program.cs):

  • Handler cookie terdaftar sebagai layanan terlingkup.
  • Layanan otorisasi terdaftar.
  • Penyedia status autentikasi kustom terdaftar sebagai layanan tercakup.
  • Antarmuka manajemen akun (IAccountManagement) terdaftar.
  • URL host dasar dikonfigurasi untuk instans klien HTTP terdaftar.
  • URL backend dasar dikonfigurasi untuk instans klien HTTP terdaftar yang digunakan untuk interaksi autentikasi dengan API web backend. Klien HTTP menggunakan cookie handler untuk memastikan bahwa cookie kredensial dikirim dengan setiap permintaan.

Panggil AuthenticationStateProvider.NotifyAuthenticationStateChanged saat status autentikasi pengguna berubah. Misalnya, lihat LoginAsync metodeCookieAuthenticationStateProvider dan LogoutAsync kelas (Identity/CookieAuthenticationStateProvider.cs).

Peringatan

Komponen AuthorizeView secara selektif menampilkan konten UI bergantung pada apakah pengguna diotorisasi. Semua konten dalam aplikasi yang Blazor WebAssembly AuthorizeView ditempatkan dalam komponen dapat ditemukan tanpa autentikasi, sehingga konten sensitif harus diperoleh dari API web berbasis server backend setelah autentikasi berhasil. Untuk informasi selengkapnya, lihat sumber daya berikut:

Menguji demonstrasi seeding pengguna

Kelas SeedData (SeedData.cs) menunjukkan cara membuat pengguna uji untuk pengembangan. Pengguna uji, bernama Leela, masuk ke aplikasi dengan alamat leela@contoso.comemail . Kata sandi pengguna diatur ke Passw0rd!. Leela diberikan Administrator dan Manager peran untuk otorisasi, yang memungkinkan pengguna untuk mengakses halaman manajer di /private-manager-page tetapi bukan halaman editor di /private-editor-page.

Peringatan

Jangan pernah mengizinkan kode pengguna pengujian berjalan di lingkungan produksi. SeedData.InitializeAsync hanya dipanggil di Development lingkungan dalam Program file:

if (builder.Environment.IsDevelopment())
{
    await using var scope = app.Services.CreateAsyncScope();
    await SeedData.InitializeAsync(scope.ServiceProvider);
}

Peran

Karena masalah desain kerangka kerja (dotnet/aspnetcore #50037), klaim peran tidak dikirim kembali dari manage/info titik akhir untuk membuat klaim pengguna untuk pengguna BlazorWasmAuth aplikasi. Klaim peran dikelola secara independen melalui permintaan terpisah dalam GetAuthenticationStateAsync metodeCookieAuthenticationStateProvider kelas (Identity/CookieAuthenticationStateProvider.cs) setelah pengguna diautentikasi dalam Backend proyek.

CookieAuthenticationStateProviderDalam , permintaan peran dibuat ke /roles titik Backend akhir proyek API server. Respons dibaca ke dalam string dengan memanggil ReadAsStringAsync(). JsonSerializer.Deserialize mendeserialisasi string ke dalam array kustom RoleClaim . Terakhir, klaim ditambahkan ke koleksi klaim pengguna.

Backend Dalam file API Program server, API Minimal mengelola /roles titik akhir. Klaim dipilih ke dalam jenis anonim dan diserialisasikan RoleClaimType untuk kembali ke BlazorWasmAuth proyek dengan TypedResults.Json.

Titik akhir peran memerlukan otorisasi dengan memanggil RequireAuthorization. Jika Anda memutuskan untuk tidak menggunakan API Minimal demi pengontrol untuk titik akhir API server yang aman, pastikan untuk mengatur [Authorize] atribut pada pengontrol atau tindakan.

Hosting lintas domain (konfigurasi situs yang sama)

Aplikasi sampel dikonfigurasi untuk menghosting kedua aplikasi di domain yang sama. Jika Anda menghosting Backend aplikasi di domain yang berbeda dari BlazorWasmAuth aplikasi, batalkan komentar kode yang mengonfigurasi cookie (ConfigureApplicationCookie) dalam Backend file aplikasi Program . Nilai defaultnya adalah:

Ubah nilai menjadi:

- options.Cookie.SameSite = SameSiteMode.Lax;
- options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
+ options.Cookie.SameSite = SameSiteMode.None;
+ options.Cookie.SecurePolicy = CookieSecurePolicy.Always;

Untuk informasi selengkapnya tentang pengaturan situs cookie yang sama, lihat sumber daya berikut ini:

Dukungan antiforgery

Hanya titik akhir keluar (/logout) di aplikasi yang Backend memerlukan perhatian untuk mengurangi ancaman Pemalsuan Permintaan Lintas Situs (CSRF).

Titik akhir keluar memeriksa isi kosong untuk mencegah serangan CSRF. Dengan memerlukan isi, permintaan harus dibuat dari JavaScript, yang merupakan satu-satunya cara untuk mengakses autentikasi cookie. Titik akhir keluar tidak dapat diakses oleh POST berbasis formulir. Ini mencegah situs berbahaya mengeluarkan pengguna.

Selain itu, titik akhir dilindungi oleh otorisasi (RequireAuthorization) untuk mencegah akses anonim.

Aplikasi BlazorWasmAuth klien hanya diperlukan untuk meneruskan objek {} kosong dalam isi permintaan.

Di luar titik akhir keluar, mitigasi antiforgery hanya diperlukan saat mengirimkan data formulir ke server yang dikodekan sebagai application/x-www-form-urlencoded, , multipart/form-dataatau text/plain. Blazor mengelola mitigasi CSRF untuk formulir dalam banyak kasus. Untuk informasi selengkapnya, lihat ringkasan autentikasi dan otorisasi core ASP.NET Blazor Core dan formulir ASP.NET CoreBlazor.

Permintaan ke titik akhir API server (API web) lain dengan application/jsonkonten yang dikodekan dan CORS diaktifkan tidak memerlukan perlindungan CSRF. Inilah sebabnya mengapa tidak ada perlindungan CSRF yang diperlukan untuk Backend titik akhir pemrosesan data (/data-processing) aplikasi. Titik akhir peran (/roles) tidak memerlukan perlindungan CSRF karena ini adalah titik akhir GET yang tidak mengubah status apa pun.

Pecahkan masalah

Pencatatan

Untuk mengaktifkan pengelogan debug atau pelacakan untuk Blazor WebAssembly autentikasi, lihat pengelogan ASP.NET CoreBlazor.

Kesalahan umum

Periksa konfigurasi setiap proyek. Konfirmasikan bahwa URL sudah benar:

  • Backend proyek
    • appsettings.json
      • BackendUrl
      • FrontendUrl
    • Backend.http: Backend_HostAddress
  • BlazorWasmAuth proyek: wwwroot/appsettings.json
    • BackendUrl
    • FrontendUrl

Jika konfigurasi muncul dengan benar:

  • Menganalisis log aplikasi.

  • Periksa lalu lintas jaringan antara BlazorWasmAuth aplikasi dan Backend aplikasi dengan alat pengembang browser. Seringkali, pesan kesalahan yang tepat atau pesan dengan petunjuk tentang apa yang menyebabkan masalah dikembalikan ke klien oleh aplikasi backend setelah membuat permintaan. Alat pengembang panduan ditemukan dalam artikel berikut:

  • Google Chrome (dokumentasi Google)

  • Microsoft Edge

  • Mozilla Firefox (dokumentasi Mozilla)

Tim dokumentasi menanggapi umpan balik dokumen dan bug dalam artikel. Buka masalah menggunakan tautan Buka masalah dokumentasi di bagian bawah artikel. Tim tidak dapat memberikan dukungan produk. Beberapa forum dukungan publik tersedia untuk membantu memecahkan masalah aplikasi. Kami merekomendasikan hal-hal berikut:

Forum sebelumnya tidak dimiliki atau dikendalikan oleh Microsoft.

Untuk laporan bug kerangka kerja non-keamanan, non-sensitif, dan non-rahasia yang dapat direproduksi, buka masalah dengan unit produk ASP.NET Core. Jangan buka masalah dengan unit produk sampai Anda menyelidiki penyebab masalah secara menyeluruh dan tidak dapat menyelesaikannya sendiri dan dengan bantuan komunitas di forum dukungan publik. Unit produk tidak dapat memecahkan masalah aplikasi individual yang rusak karena kesalahan konfigurasi sederhana atau kasus penggunaan yang melibatkan layanan pihak ketiga. Jika laporan bersifat sensitif atau rahasia atau menggambarkan potensi kelemahan keamanan dalam produk yang dapat dieksploitasi penyerang, lihat Melaporkan masalah keamanan dan bug (dotnet/aspnetcore repositori GitHub).

Cookies dan data situs

Cookiedata s dan situs dapat bertahan di seluruh pembaruan aplikasi dan mengganggu pengujian dan pemecahan masalah. Hapus hal berikut saat membuat perubahan kode aplikasi, perubahan akun pengguna, atau perubahan konfigurasi aplikasi:

  • Rincian masuk cookiepengguna
  • Aplikasi cookies
  • Data situs yang di-cache dan disimpan

Salah satu pendekatan untuk mencegah cookiedata situs dan yang masih ada mengganggu pengujian dan pemecahan masalah adalah dengan:

  • Mengonfigurasi browser
    • Gunakan browser untuk pengujian yang dapat Anda konfigurasi untuk menghapus semua cookie dan data situs setiap kali browser ditutup.
    • Pastikan browser ditutup secara manual atau oleh IDE untuk setiap perubahan pada aplikasi, pengguna uji, atau konfigurasi penyedia.
  • Gunakan perintah kustom untuk membuka browser dalam mode InPrivate atau Penyamaran di Visual Studio:
    • Buka kotak dialog Telusuri Dengan dari tombol Jalankan Visual Studio.
    • Pilih tombol Tambahkan.
    • Berikan jalur ke browser Anda di bidang Program . Jalur yang dapat dieksekusi berikut adalah lokasi penginstalan umum untuk Windows 10. Jika browser Anda diinstal di lokasi yang berbeda atau Anda tidak menggunakan Windows 10, berikan jalur ke browser yang dapat dieksekusi.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • Di bidang Argumen, berikan opsi baris perintah yang digunakan browser untuk membuka dalam mode InPrivate atau Penyamaran. Beberapa browser memerlukan URL aplikasi.
      • Microsoft Edge: Gunakan -inprivate.
      • Google Chrome: Gunakan --incognito --new-window {URL}, di mana {URL} tempat penampung adalah URL untuk dibuka (misalnya, https://localhost:5001).
      • Mozilla Firefox: Gunakan -private -url {URL}, di mana {URL} tempat penampung adalah URL untuk dibuka (misalnya, https://localhost:5001).
    • Berikan nama di bidang Nama yang mudah diingat. Contohnya,Firefox Auth Testing.
    • Pilih tombol OK.
    • Untuk menghindari harus memilih profil browser untuk setiap iterasi pengujian dengan aplikasi, atur profil sebagai default dengan tombol Atur sebagai Default .
    • Pastikan bahwa browser ditutup oleh IDE untuk setiap perubahan pada aplikasi, pengguna uji, atau konfigurasi penyedia.

Peningkatan aplikasi

Aplikasi yang berfungsi mungkin gagal segera setelah meningkatkan .NET Core SDK pada komputer pengembangan atau mengubah versi paket dalam aplikasi. Dalam beberapa kasus, paket yang tidak melekat dapat merusak aplikasi saat melakukan peningkatan besar. Sebagian besar masalah ini dapat diperbaiki dengan mengikuti instruksi berikut:

  1. Hapus cache paket NuGet sistem lokal dengan mengeksekusi dotnet nuget locals all --clear dari shell perintah.
  2. Hapus folder dan obj proyekbin.
  3. Pulihkan dan bangun ulang proyek.
  4. Hapus semua file di folder penyebaran di server sebelum menyebarkan ulang aplikasi.

Catatan

Penggunaan versi paket yang tidak kompatibel dengan kerangka kerja target aplikasi tidak didukung. Untuk informasi tentang paket, gunakan Galeri NuGet atau Penjelajah Paket FuGet.

Memeriksa klaim pengguna

Untuk memecahkan masalah dengan klaim pengguna, komponen berikut UserClaims dapat digunakan langsung di aplikasi atau berfungsi sebagai dasar untuk penyesuaian lebih lanjut.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

**Name**: @AuthenticatedUser?.Identity?.Name

<h2>Claims</h2>

@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
    <p class="claim">@(claim.Type): @claim.Value</p>
}

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? AuthenticationState { get; set; }

    public ClaimsPrincipal? AuthenticatedUser { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthenticationState is not null)
        {
            var state = await AuthenticationState;
            AuthenticatedUser = state.User;
        }
    }
}

Sumber Daya Tambahan: