Bagikan melalui


Cara menggunakan Identity untuk mengamankan backend API Web untuk SPAs

Catatan

Ini bukan versi terbaru dari artikel ini. 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 8 dari artikel ini.

ASP.NET Core Identity menyediakan API yang menangani autentikasi, otorisasi, dan manajemen identitas. API memungkinkan untuk mengamankan titik akhir backend API Web dengan cookieautentikasi berbasis. Ada opsi berbasis token untuk klien yang tidak dapat menggunakannya cookie.

Artikel ini menunjukkan cara menggunakan Identity untuk mengamankan backend API Web untuk SPAs seperti aplikasi Angular, React, dan Vue. API backend yang sama dapat digunakan untuk mengamankan Blazor WebAssembly aplikasi.

Prasyarat

Langkah-langkah yang ditunjukkan dalam artikel ini menambahkan autentikasi dan otorisasi ke aplikasi ASP.NET Core Web API yang:

  • Belum dikonfigurasi untuk autentikasi.
  • Target atau yang lebih net8.0 baru.
  • Dapat berupa API minimal atau API berbasis pengontrol.

Beberapa instruksi pengujian dalam artikel ini menggunakan antarmuka pengguna Swagger yang disertakan dengan templat proyek. Antarmuka pengguna Swagger tidak diperlukan untuk digunakan Identity dengan backend API Web.

Instal paket NuGet

Instal paket NuGet berikut:

Untuk cara tercepat untuk memulai, gunakan database dalam memori.

Ubah database nanti ke SQLite atau SQL Server untuk menyimpan data pengguna antar sesi saat menguji atau untuk penggunaan produksi. Itu memperkenalkan beberapa kompleksitas dibandingkan dengan dalam memori, karena mengharuskan database dibuat melalui migrasi, seperti yang EF Core ditunjukkan dalam tutorial memulai.

Instal paket ini dengan menggunakan manajer paket NuGet di Visual Studio atau perintah CLI tambahkan paket dotnet.

Buat IdentityDbContext

Tambahkan kelas bernama ApplicationDbContext yang mewarisi dari IdentityDbContext<TUser>:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
        base(options)
    { }
}

Kode yang ditampilkan menyediakan konstruktor khusus yang memungkinkan untuk mengonfigurasi database untuk lingkungan yang berbeda.

Tambahkan satu atau beberapa arahan berikut sesuai using kebutuhan saat menambahkan kode yang diperlihatkan dalam langkah-langkah ini.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

EF Core Mengonfigurasi konteks

Seperti disebutkan sebelumnya, cara paling sederhana untuk memulai adalah dengan menggunakan database dalam memori. Dengan setiap eksekusi dalam memori dimulai dengan database baru, dan tidak perlu menggunakan migrasi. Setelah panggilan ke WebApplication.CreateBuilder(args), tambahkan kode berikut untuk dikonfigurasi Identity untuk menggunakan database dalam memori:

builder.Services.AddDbContext<ApplicationDbContext>(
    options => options.UseInMemoryDatabase("AppDb"));

Untuk menyimpan data pengguna antar sesi saat menguji atau untuk penggunaan produksi, ubah database nanti ke SQLite atau SQL Server.

Menambahkan Identity layanan ke kontainer

Setelah panggilan ke WebApplication.CreateBuilder(args), panggil AddAuthorization untuk menambahkan layanan ke kontainer injeksi dependensi (DI):

builder.Services.AddAuthorization();

Mengaktifkan Identity API

Setelah panggilan ke WebApplication.CreateBuilder(args), panggil AddIdentityApiEndpoints<TUser>(IServiceCollection) dan AddEntityFrameworkStores<TContext>(IdentityBuilder).

builder.Services.AddIdentityApiEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Secara default, token cookies dan kepemilikan diaktifkan. Cookies dan token dikeluarkan saat masuk jika useCookies parameter string kueri di titik akhir login adalah true.

Rute peta Identity

Setelah panggilan ke builder.Build(), panggil MapIdentityApi<TUser>(IEndpointRouteBuilder) untuk memetakan Identity titik akhir:

app.MapIdentityApi<IdentityUser>();

Mengamankan titik akhir yang dipilih

Untuk mengamankan titik akhir, gunakan RequireAuthorization metode ekstensi pada Map{Method} panggilan yang menentukan rute. Contohnya:

app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        })
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();

Metode ini RequireAuthorization juga dapat digunakan untuk:

  • Titik akhir UI Swagger Aman, seperti yang ditunjukkan dalam contoh berikut:

    app.MapSwagger().RequireAuthorization();
    
  • Amankan dengan klaim atau izin tertentu, seperti yang ditunjukkan dalam contoh berikut:

    .RequireAuthorization("Admin");
    

Dalam proyek API web berbasis pengontrol, titik akhir aman dengan menerapkan atribut [Authorize] ke pengontrol atau tindakan.

Menguji API

Cara cepat untuk menguji autentikasi adalah dengan menggunakan database dalam memori dan antarmuka pengguna Swagger yang disertakan dengan templat proyek. Langkah-langkah berikut menunjukkan cara menguji API dengan antarmuka pengguna Swagger. Pastikan bahwa titik akhir antarmuka pengguna Swagger tidak diamankan.

Mencoba mengakses titik akhir aman

  • Jalankan aplikasi dan navigasikan ke antarmuka pengguna Swagger.
  • Perluas titik akhir aman, seperti /weatherforecast dalam proyek yang dibuat oleh templat API web.
  • Pilih Coba.
  • Pilih Jalankan. Responsnya adalah 401 - not authorized.

Uji pendaftaran

  • Perluas /register dan pilih Cobalah.

  • Di bagian Parameter UI, isi permintaan sampel ditampilkan:

    {
      "email": "string",
      "password": "string"
    }
    
  • Ganti "string" dengan alamat email dan kata sandi yang valid, lalu pilih Jalankan.

    Untuk mematuhi aturan validasi kata sandi default, panjang kata sandi harus setidaknya enam karakter dan berisi setidaknya satu dari masing-masing karakter berikut:

    • Huruf besar
    • Huruf kecil
    • Digit numerik
    • Karakter non-nufanumerik

    Jika Anda memasukkan alamat email yang tidak valid atau kata sandi yang buruk, hasilnya menyertakan kesalahan validasi. Berikut adalah contoh isi respons dengan kesalahan validasi:

    {
      "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
      "title": "One or more validation errors occurred.",
      "status": 400,
      "errors": {
        "PasswordTooShort": [
          "Passwords must be at least 6 characters."
        ],
        "PasswordRequiresNonAlphanumeric": [
          "Passwords must have at least one non alphanumeric character."
        ],
        "PasswordRequiresDigit": [
          "Passwords must have at least one digit ('0'-'9')."
        ],
        "PasswordRequiresLower": [
          "Passwords must have at least one lowercase ('a'-'z')."
        ]
      }
    }
    

    Kesalahan dikembalikan dalam format ProblemDetails sehingga klien dapat mengurainya dan menampilkan kesalahan validasi sesuai kebutuhan.

    Pendaftaran yang berhasil menghasilkan 200 - OK respons.

Uji login

  • Perluas /login dan pilih Cobalah. Contoh isi permintaan menunjukkan dua parameter tambahan:

    {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
      "twoFactorRecoveryCode": "string"
    }
    

    Properti ON tambahan JStidak diperlukan untuk contoh ini dan dapat dihapus. Atur useCookies ke true.

  • Ganti "string" dengan alamat email dan kata sandi yang Anda gunakan untuk mendaftar, lalu pilih Jalankan.

    Login yang berhasil menghasilkan 200 - OK respons dengan cookie di header respons.

Coba lagi titik akhir aman

Setelah berhasil masuk, jalankan ulang titik akhir aman. Autentikasi cookie dikirim secara otomatis dengan permintaan, dan titik akhir diotorisasi. CookieAutentikasi berbasis aman bawaan ke browser dan "hanya berfungsi."

Pengujian dengan klien nonbrowser

Beberapa klien web mungkin tidak menyertakan cookies di header secara default:

  • Jika Anda menggunakan alat untuk menguji API, Anda mungkin perlu mengaktifkannya cookiedi pengaturan.

  • API JavaScript fetch tidak menyertakan cookiesecara default. Aktifkan dengan mengatur credentials ke nilai include dalam opsi.

  • Yang HttpClient berjalan di Blazor WebAssembly aplikasi memerlukan HttpRequestMessage untuk menyertakan kredensial, seperti contoh berikut:

    request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
    

Menggunakan autentikasi berbasis token

Untuk klien yang tidak mendukung cookie, API login menyediakan parameter untuk meminta token. Token kustom (yang merupakan milik platform identitas ASP.NET Core) dikeluarkan yang dapat digunakan untuk mengautentikasi permintaan berikutnya. Token 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 berfitur lengkap atau server token, tetapi sebagai alternatif untuk cookie opsi untuk klien yang tidak dapat menggunakannya cookie.

Untuk menggunakan autentikasi berbasis token, atur useCookies parameter string kueri ke false saat memanggil /login titik akhir. Token menggunakan skema autentikasi pembawa . Menggunakan token yang dikembalikan dari panggilan ke /login, panggilan berikutnya ke titik akhir yang dilindungi harus menambahkan header Authorization: Bearer <token> di mana <token> adalah token akses. Untuk informasi selengkapnya, lihat Menggunakan POST /login titik akhir nanti di artikel ini.

Keluar

Untuk menyediakan cara bagi pengguna untuk keluar, tentukan /logout titik akhir seperti contoh berikut:

app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
    [FromBody] object empty) =>
{
    if (empty != null)
    {
        await signInManager.SignOutAsync();
        return Results.Ok();
    }
    return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();

Berikan objek ON kosong JS({}) di isi permintaan saat memanggil titik akhir ini. Kode berikut adalah contoh panggilan ke titik akhir keluar:

public signOut() {
  return this.http.post('/logout', {}, {
    withCredentials: true,
    observe: 'response',
    responseType: 'text'

Titik MapIdentityApi<TUser> akhir

Panggilan untuk MapIdentityApi<TUser> menambahkan titik akhir berikut ke aplikasi:

POST /register Menggunakan titik akhir

Isi permintaan harus memiliki Email properti dan Password :

{
  "email": "string",
  "password": "string",
}

Untuk informasi selengkapnya, lihat:

POST /login Menggunakan titik akhir

Dalam isi permintaan, Email dan Password diperlukan. Jika autentikasi dua faktor (2FA) diaktifkan, baik TwoFactorCode atau TwoFactorRecoveryCode diperlukan. Jika 2FA tidak diaktifkan, hilangkan keduanya twoFactorCode dan twoFactorRecoveryCode. Untuk informasi selengkapnya, lihat Menggunakan POST /manage/2fa titik akhir nanti di artikel ini.

Berikut adalah contoh isi permintaan dengan 2FA tidak diaktifkan:

{
  "email": "string",
  "password": "string"
}

Berikut adalah contoh isi permintaan dengan 2FA diaktifkan:

  • {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
    }
    
  • {
      "email": "string",
      "password": "string",
      "twoFactorRecoveryCode": "string"
    }
    

Titik akhir mengharapkan parameter string kueri:

  • useCookies - Atur ke true untuk cookieautentikasi berbasis. Atur ke false atau hilangkan untuk autentikasi berbasis token.

Untuk informasi selengkapnya tentang cookieautentikasi berbasis, lihat Menguji login sebelumnya di artikel ini.

Autentikasi berbasis token

Jika useCookies atau dihilangkan false , autentikasi berbasis token diaktifkan. Isi respons mencakup properti berikut:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

Untuk informasi selengkapnya tentang properti ini, lihat AccessTokenResponse.

Letakkan token akses di header untuk membuat permintaan terautentikasi, seperti yang ditunjukkan dalam contoh berikut

Authorization: Bearer {access token}

Saat token akses akan kedaluwarsa, panggil titik akhir /refresh .

POST /refresh Menggunakan titik akhir

Untuk digunakan hanya dengan autentikasi berbasis token. Mendapatkan token akses baru tanpa memaksa pengguna untuk masuk lagi. Panggil titik akhir ini saat token akses akan kedaluwarsa.

Isi permintaan hanya RefreshTokenberisi . Berikut adalah contoh isi permintaan:

{
  "refreshToken": "string"
}

Jika panggilan berhasil, isi respons adalah baru AccessTokenResponse, seperti yang ditunjukkan dalam contoh berikut:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

GET /confirmEmail Menggunakan titik akhir

Jika Identity disiapkan untuk konfirmasi email, panggilan yang berhasil ke /register titik akhir akan mengirim email yang berisi tautan ke /confirmEmail titik akhir. Tautan berisi parameter string kueri berikut:

  • userId
  • code
  • changedEmail - Disertakan hanya jika pengguna mengubah alamat email selama pendaftaran.

Identity menyediakan teks default untuk email konfirmasi. Secara default, subjek email adalah "Konfirmasi email Anda" dan isi email terlihat seperti contoh berikut:

 Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.

RequireConfirmedEmail Jika properti diatur ke true, pengguna tidak dapat masuk hingga alamat email dikonfirmasi dengan mengklik tautan dalam email. Titik /confirmEmail akhir:

  • Mengonfirmasi alamat email dan memungkinkan pengguna untuk masuk.
  • Mengembalikan teks "Terima kasih telah mengonfirmasi email Anda." di isi respons.

Untuk menyiapkan Identity konfirmasi email, tambahkan kode untuk Program.cs diatur RequireConfirmedEmail ke true dan tambahkan kelas yang diterapkan IEmailSender ke kontainer DI. Contohnya:

builder.Services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = true;
});

builder.Services.AddTransient<IEmailSender, EmailSender>();

Untuk informasi selengkapnya, lihat Konfirmasi akun dan pemulihan kata sandi di ASP.NET Core.

Identity menyediakan teks default untuk email lain yang perlu dikirim juga, seperti untuk 2FA dan pengaturan ulang kata sandi. Untuk menyesuaikan email ini, berikan implementasi IEmailSender kustom antarmuka. Dalam contoh sebelumnya, EmailSender adalah kelas yang mengimplementasikan IEmailSender. Untuk informasi selengkapnya, termasuk contoh kelas yang menerapkan IEmailSender, lihat Konfirmasi akun dan pemulihan kata sandi di ASP.NET Core.

POST /resendConfirmationEmail Menggunakan titik akhir

Mengirim email hanya jika alamat tersebut valid untuk pengguna terdaftar.

Isi permintaan hanya Emailberisi . Berikut adalah contoh isi permintaan:

{
  "email": "string"
}

Untuk informasi selengkapnya, lihat Menggunakan GET /confirmEmail titik akhir sebelumnya di artikel ini.

POST /forgotPassword Menggunakan titik akhir

Menghasilkan email yang berisi kode reset kata sandi. Kirim kode tersebut ke /resetPassword dengan kata sandi baru.

Isi permintaan hanya Emailberisi . Berikut contohnya:

{
  "email": "string"
}

Untuk informasi tentang cara mengaktifkan Identity untuk mengirim email, lihat Menggunakan GET /confirmEmail titik akhir.

POST /resetPassword Menggunakan titik akhir

Panggil titik akhir ini setelah mendapatkan kode reset dengan memanggil /forgotPassword titik akhir.

Isi permintaan memerlukan Email, , ResetCodedan NewPassword. Berikut contohnya:

{
  "email": "string",
  "resetCode": "string",
  "newPassword": "string"
}

POST /manage/2fa Menggunakan titik akhir

Mengonfigurasi autentikasi dua faktor (2FA) untuk pengguna. Ketika 2FA diaktifkan, login yang berhasil memerlukan kode yang dihasilkan oleh aplikasi pengautentikasi selain alamat email dan kata sandi.

Aktifkan 2FA

Untuk mengaktifkan 2FA untuk pengguna yang saat ini diautentikasi:

  • /manage/2fa Panggil titik akhir, kirim objek ON kosong JS({}) di isi permintaan.

  • Isi respons menyediakan SharedKey bersama dengan beberapa properti lain yang tidak diperlukan pada saat ini. Kunci bersama digunakan untuk menyiapkan aplikasi pengautentikasi. Contoh badan respons:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 0,
      "recoveryCodes": null,
      "isTwoFactorEnabled": false,
      "isMachineRemembered": false
    }
    
  • Gunakan kunci bersama untuk mendapatkan kata sandi satu kali berbasis waktu (TOTP). Untuk informasi selengkapnya, lihat Mengaktifkan pembuatan kode QR untuk aplikasi pengautentikasi TOTP di ASP.NET Core.

  • /manage/2fa Panggil titik akhir, kirim TOTP dan "enable": true di isi permintaan. Contohnya:

    {
      "enable": true,
      "twoFactorCode": "string"
    }
    
  • Isi respons mengonfirmasi bahwa IsTwoFactorEnabled itu benar dan menyediakan RecoveryCodes. Kode pemulihan digunakan untuk masuk saat aplikasi pengautentikasi tidak tersedia. Contoh isi respons setelah berhasil mengaktifkan 2FA:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 10,
      "recoveryCodes": [
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string"
      ],
      "isTwoFactorEnabled": true,
      "isMachineRemembered": false
    }
    

Masuk dengan 2FA

/login Panggil titik akhir, kirim alamat email, kata sandi, dan TOTP di isi permintaan. Contohnya:

{
  "email": "string",
  "password": "string",
  "twoFactorCode": "string"
}

Jika pengguna tidak memiliki akses ke aplikasi pengautentikasi, masuk dengan memanggil /login titik akhir dengan salah satu kode pemulihan yang disediakan saat 2FA diaktifkan. Isi permintaan terlihat seperti contoh berikut:

{
  "email": "string",
  "password": "string",
  "twoFactorRecoveryCode": "string"
}

Mengatur ulang kode pemulihan

Untuk mendapatkan kumpulan kode pemulihan baru, panggil titik akhir ini dengan ResetRecoveryCodes diatur ke true. Berikut adalah contoh isi permintaan:

{
  "resetRecoveryCodes": true
}

Mereset kunci bersama

Untuk mendapatkan kunci bersama acak baru, panggil titik akhir ini dengan ResetSharedKey diatur ke true. Berikut adalah contoh isi permintaan:

{
  "resetSharedKey": true
}

Mengatur ulang kunci secara otomatis menonaktifkan persyaratan masuk dua faktor untuk pengguna yang diautentikasi hingga diaktifkan kembali oleh permintaan selanjutnya.

Lupakan mesin

Untuk menghapus cookie "ingat bendera saya" jika ada, panggil titik akhir ini dengan ForgetMachine diatur ke true. Berikut adalah contoh isi permintaan:

{
  "forgetMachine": true
}

Titik akhir ini tidak berdampak pada autentikasi berbasis token.

GET /manage/info Menggunakan titik akhir

Mendapatkan alamat email dan status konfirmasi email pengguna yang masuk. Klaim dihilangkan dari titik akhir ini karena alasan keamanan. Jika klaim diperlukan, gunakan API sisi server untuk menyiapkan titik akhir untuk klaim. Atau alih-alih membagikan semua klaim pengguna, berikan titik akhir validasi yang menerima klaim dan merespons apakah pengguna memilikinya.

Permintaan tidak memerlukan parameter apa pun. Isi respons mencakup Email properti dan IsEmailConfirmed , seperti dalam contoh berikut:

{
  "email": "string",
  "isEmailConfirmed": true
}

POST /manage/info Menggunakan titik akhir

Memperbarui alamat email dan kata sandi pengguna yang masuk. Kirim NewEmail, NewPassword, dan OldPassword dalam isi permintaan, seperti yang ditunjukkan dalam contoh berikut:

{
  "newEmail": "string",
  "newPassword": "string",
  "oldPassword": "string"
}

Berikut contoh isi responsnya:

{
  "email": "string",
  "isEmailConfirmed": false
}

Lihat juga

Untuk informasi selengkapnya, lihat sumber daya berikut:

Templat ASP.NET Core menawarkan autentikasi di Aplikasi Halaman Tunggal (SPAs) menggunakan dukungan untuk otorisasi API. ASP.NET Core Identity untuk mengautentikasi dan menyimpan pengguna dikombinasikan dengan Duende Identity Server untuk menerapkan Koneksi OpenID.

Penting

Perangkat Lunak Duende mungkin mengharuskan Anda membayar biaya lisensi untuk penggunaan produksi Server Identity Duende. Untuk informasi lebih lanjut, lihat Bermigrasi dari ASP.NET Core 5.0 ke 6.0.

Parameter autentikasi ditambahkan ke templat proyek Angular dan React yang mirip dengan parameter autentikasi di templat proyek Aplikasi Web (Model-View-Controller) (MVC) dan Aplikasi Web (Razor Halaman). Nilai parameter yang diizinkan adalah Tidak Ada dan Individual. Templat proyek React.js dan Redux saat ini tidak mendukung parameter autentikasi.

Membuat aplikasi dengan dukungan otorisasi API

Autentikasi dan otorisasi pengguna dapat digunakan dengan Angular dan React SPAs. Buka shell perintah, dan jalankan perintah berikut:

Sudut:

dotnet new angular -au Individual

React:

dotnet new react -au Individual

Perintah sebelumnya membuat aplikasi ASP.NET Core dengan direktori ClientApp yang berisi SPA.

Deskripsi umum komponen ASP.NET Core aplikasi

Bagian berikut menjelaskan penambahan ke proyek saat dukungan autentikasi disertakan:

Program.cs

Contoh kode berikut mengandalkan Microsoft.AspNetCore.ApiAuthorization.IdentityPaket NuGet Server . Contoh mengonfigurasi autentikasi dan otorisasi API menggunakan AddApiAuthorization metode ekstensi dan AddIdentityServerJwt . Proyek yang menggunakan templat proyek React atau Angular SPA dengan autentikasi menyertakan referensi ke paket ini.

dotnet new angular -au Individual menghasilkan file berikut Program.cs :

using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Kode sebelumnya mengonfigurasi:

  • Identity dengan UI default:

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlite(connectionString));
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
    
    builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
  • IdentityServer dengan metode pembantu Identitytambahan AddApiAuthorization yang menyiapkan beberapa konvensi ASP.NET Core default di atas Server:

    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
    
  • Autentikasi dengan metode pembantu tambahan AddIdentityServerJwt yang mengonfigurasi aplikasi untuk memvalidasi token JWT yang diproduksi oleh IdentityServer:

    builder.Services.AddAuthentication()
    .AddIdentityServerJwt();
    
  • Middleware autentikasi yang bertanggung jawab untuk memvalidasi kredensial permintaan dan mengatur pengguna pada konteks permintaan:

    app.UseAuthentication();
    
  • IdentityMiddleware Server yang mengekspos titik akhir Koneksi OpenID:

    app.UseIdentityServer();
    

Azure App Service di Linux

Untuk penyebaran Azure App Service di Linux, tentukan penerbit secara eksplisit:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

Dalam kode sebelumnya, {AUTHORITY} tempat penampung adalah Authority untuk digunakan saat melakukan panggilan Koneksi OpenID.

Contoh:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Metode pembantu Identityini mengonfigurasi Server untuk menggunakan konfigurasi kami yang didukung. IdentityServer adalah kerangka kerja yang kuat dan dapat diperluas untuk menangani masalah keamanan aplikasi. Pada saat yang sama, yang mengekspos kompleksitas yang tidak perlu untuk skenario yang paling umum. Akibatnya, serangkaian konvensi dan opsi konfigurasi disediakan untuk Anda yang dianggap sebagai titik awal yang baik. Setelah autentikasi Anda perlu berubah, kekuatan Identitypenuh Server masih tersedia untuk menyesuaikan autentikasi agar sesuai dengan kebutuhan Anda.

AddIdentityServerJwt

Metode pembantu ini mengonfigurasi skema kebijakan untuk aplikasi sebagai penangan autentikasi default. Kebijakan dikonfigurasi untuk memungkinkan Identity menangani semua permintaan yang dirutekan ke subpath apa pun di Identity ruang URL "/Identity". Menangani JwtBearerHandler semua permintaan lainnya. Selain itu, metode ini mendaftarkan <<ApplicationName>>API sumber daya API dengan IdentityServer dengan cakupan <<ApplicationName>>API default dan mengonfigurasi middleware token Pembawa JWT untuk memvalidasi token yang dikeluarkan oleh IdentityServer untuk aplikasi.

WeatherForecastController

Dalam file, perhatikan [Authorize] atribut yang diterapkan ke kelas yang menunjukkan bahwa pengguna perlu diotorisasi berdasarkan kebijakan default untuk mengakses sumber daya. Kebijakan otorisasi default kebetulan dikonfigurasi untuk menggunakan skema autentikasi default, yang disiapkan oleh AddIdentityServerJwt ke skema kebijakan yang disebutkan di atas, menjadikan JwtBearerHandler dikonfigurasi oleh metode pembantu tersebut sebagai handler default untuk permintaan ke aplikasi.

ApplicationDbContext

Dalam file, perhatikan bahwa hal yang sama DbContext digunakan dengan Identity pengecualian bahwa ia memperluas ApiAuthorizationDbContext (kelas yang lebih turunan dari IdentityDbContext) untuk menyertakan skema untuk IdentityServer.

Untuk mendapatkan kontrol penuh atas skema database, warisi dari salah satu kelas yang tersedia IdentityDbContext dan konfigurasikan konteks untuk menyertakan Identity skema dengan memanggil builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value)OnModelCreating metode .

OidcConfigurationController

Dalam file, perhatikan titik akhir yang disediakan untuk melayani parameter OIDC yang perlu digunakan klien.

appsettings.json

appsettings.json Dalam file akar proyek, ada bagian baru IdentityServer yang menjelaskan daftar klien yang dikonfigurasi. Dalam contoh berikut, ada satu klien. Nama klien sesuai dengan nama aplikasi dan dipetakan berdasarkan konvensi ke parameter OAuth ClientId . Profil menunjukkan jenis aplikasi yang sedang dikonfigurasi. Ini digunakan secara internal untuk mendorong konvensi yang menyederhanakan proses konfigurasi untuk server. Ada beberapa profil yang tersedia, seperti yang dijelaskan di bagian Profil aplikasi.

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

appsettings.Development.json Dalam file akar proyek, ada IdentityServer bagian yang menjelaskan kunci yang digunakan untuk menandatangani token. Saat menyebarkan ke produksi, kunci perlu disediakan dan disebarkan bersama aplikasi, seperti yang dijelaskan di bagian Sebarkan ke produksi .

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Deskripsi umum aplikasi Angular

Dukungan autentikasi dan otorisasi API dalam templat Angular berada dalam modul Angularnya sendiri di direktori ClientApp/src/api-authorization . Modul ini terdiri dari elemen-elemen berikut:

  • 3 komponen:
    • login.component.ts: Menangani alur masuk aplikasi.
    • logout.component.ts: Menangani alur keluar aplikasi.
    • login-menu.component.ts: Widget yang menampilkan salah satu set tautan berikut:
      • Manajemen profil pengguna dan tautan keluar saat pengguna diautentikasi.
      • Tautan pendaftaran dan masuk saat pengguna tidak diautentikasi.
  • Penjaga AuthorizeGuard rute yang dapat ditambahkan ke rute dan mengharuskan pengguna untuk diautentikasi sebelum mengunjungi rute.
  • Pencegat AuthorizeInterceptor HTTP yang melampirkan token akses ke permintaan HTTP keluar yang menargetkan API saat pengguna diautentikasi.
  • Layanan AuthorizeService yang menangani detail tingkat bawah proses autentikasi dan mengekspos informasi tentang pengguna yang diautentikasi ke aplikasi lainnya untuk dikonsumsi.
  • Modul Angular yang menentukan rute yang terkait dengan bagian autentikasi aplikasi. Ini mengekspos komponen menu login, pencegat, penjaga, dan layanan untuk dikonsumsi dari aplikasi lainnya.

Deskripsi umum aplikasi React

Dukungan untuk autentikasi dan otorisasi API di templat React berada di direktori ClientApp/src/components/api-authorization . Ini terdiri dari elemen-elemen berikut:

  • 4 komponen:
    • Login.js: Menangani alur masuk aplikasi.
    • Logout.js: Menangani alur keluar aplikasi.
    • LoginMenu.js: Widget yang menampilkan salah satu set tautan berikut:
      • Manajemen profil pengguna dan tautan keluar saat pengguna diautentikasi.
      • Tautan pendaftaran dan masuk saat pengguna tidak diautentikasi.
    • AuthorizeRoute.js: Komponen rute yang mengharuskan pengguna diautentikasi sebelum merender komponen yang ditunjukkan dalam Component parameter .
  • Instans kelas AuthorizeService yang diekspor authService yang menangani detail tingkat bawah dari proses autentikasi dan mengekspos informasi tentang pengguna yang diautentikasi ke aplikasi lainnya untuk dikonsumsi.

Sekarang setelah Anda melihat komponen utama solusi, Anda dapat melihat skenario individual yang lebih dalam untuk aplikasi.

Memerlukan otorisasi pada API baru

Secara default, sistem dikonfigurasi untuk dengan mudah memerlukan otorisasi untuk API baru. Untuk melakukannya, buat pengontrol baru dan tambahkan [Authorize] atribut ke kelas pengontrol atau ke tindakan apa pun dalam pengontrol.

Menyesuaikan handler autentikasi API

Untuk menyesuaikan konfigurasi handler JWT API, konfigurasikan instansnya JwtBearerOptions :

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Handler JWT API meningkatkan peristiwa yang memungkinkan kontrol atas proses autentikasi menggunakan JwtBearerEvents. Untuk memberikan dukungan untuk otorisasi API, AddIdentityServerJwt daftarkan penanganan aktivitasnya sendiri.

Untuk menyesuaikan penanganan peristiwa, bungkus penanganan aktivitas yang ada dengan logika tambahan sesuai kebutuhan. Contohnya:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

Dalam kode sebelumnya, penanganan OnTokenValidated aktivitas diganti dengan implementasi kustom. Implementasi ini:

  1. Memanggil implementasi asli yang disediakan oleh dukungan otorisasi API.
  2. Jalankan logika kustomnya sendiri.

Melindungi rute sisi klien (Angular)

Melindungi rute sisi klien dilakukan dengan menambahkan penjaga otorisasi ke daftar penjaga yang akan dijalankan saat mengonfigurasi rute. Sebagai contoh, Anda dapat melihat bagaimana rute dikonfigurasi fetch-data dalam modul Angular aplikasi utama:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Penting untuk disebutkan bahwa melindungi rute tidak melindungi titik akhir aktual (yang masih memerlukan atribut yang [Authorize] diterapkan padanya) tetapi hanya mencegah pengguna menavigasi ke rute sisi klien yang diberikan saat tidak diautentikasi.

Mengautentikasi permintaan API (Angular)

Mengautentikasi permintaan ke API yang dihosting bersama aplikasi dilakukan secara otomatis melalui penggunaan pencegat klien HTTP yang ditentukan oleh aplikasi.

Melindungi rute sisi klien (React)

Lindungi rute sisi klien dengan menggunakan AuthorizeRoute komponen alih-alih komponen biasa Route . Misalnya, perhatikan bagaimana rute dikonfigurasi fetch-data dalam App komponen:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Melindungi rute:

  • Tidak melindungi titik akhir aktual (yang masih memerlukan atribut yang [Authorize] diterapkan padanya).
  • Hanya mencegah pengguna menavigasi ke rute sisi klien yang diberikan saat tidak diautentikasi.

Mengautentikasi permintaan API (React)

Mengautentikasi permintaan dengan React dilakukan dengan terlebih dahulu mengimpor authService instans dari AuthorizeService. Token akses diambil dari authService dan dilampirkan ke permintaan seperti yang ditunjukkan di bawah ini. Dalam komponen React, pekerjaan ini biasanya dilakukan dalam componentDidMount metode siklus hidup atau sebagai hasil dari beberapa interaksi pengguna.

Mengimpor ke authService dalam komponen

import authService from './api-authorization/AuthorizeService'

Mengambil dan melampirkan token akses ke respons

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Menyebarkan ke produksi

Untuk menyebarkan aplikasi ke produksi, sumber daya berikut perlu disediakan:

  • Database untuk menyimpan Identity akun pengguna dan pemberian IdentityServer.
  • Sertifikat produksi yang digunakan untuk menandatangani token.
    • Tidak ada persyaratan khusus untuk sertifikat ini; dapat berupa sertifikat yang ditandatangani sendiri atau sertifikat yang disediakan melalui otoritas CA.
    • Ini dapat dihasilkan melalui alat standar seperti PowerShell atau OpenSSL.
    • Ini dapat diinstal ke penyimpanan sertifikat pada komputer target atau disebarkan sebagai file .pfx dengan kata sandi yang kuat.

Contoh: Menyebarkan ke penyedia hosting web non-Azure

Di panel hosting web Anda, buat atau muat sertifikat Anda. Kemudian dalam file aplikasi appsettings.json , ubah bagian IdentityServer untuk menyertakan detail utama. Contohnya:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

Dalam contoh sebelumnya:

  • StoreName mewakili nama penyimpanan sertifikat tempat sertifikat disimpan. Dalam hal ini, menunjuk ke penyimpanan hosting web.
  • StoreLocation mewakili tempat memuat sertifikat dari (CurrentUser dalam hal ini).
  • Name sesuai dengan subjek khusus untuk sertifikat.

Contoh: Menyebarkan ke Azure App Service

Bagian ini menjelaskan penyebaran aplikasi ke Azure App Service menggunakan sertifikat yang disimpan di penyimpanan sertifikat. Untuk memodifikasi aplikasi untuk memuat sertifikat dari penyimpanan sertifikat, paket layanan tingkat Standar atau lebih baik diperlukan saat Anda mengonfigurasi aplikasi di portal Azure di langkah selanjutnya.

Dalam file aplikasi appsettings.json , ubah bagian IdentityServer untuk menyertakan detail utama:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Nama penyimpanan mewakili nama penyimpanan sertifikat tempat sertifikat disimpan. Dalam hal ini, ini menunjuk ke penyimpanan pengguna pribadi.
  • Lokasi penyimpanan mewakili tempat memuat sertifikat dari (CurrentUser atau LocalMachine).
  • Properti nama pada sertifikat sesuai dengan subjek khusus untuk sertifikat.

Untuk menyebarkan ke Azure App Service, ikuti langkah-langkah dalam Menyebarkan aplikasi ke Azure, yang menjelaskan cara membuat sumber daya Azure yang diperlukan dan menyebarkan aplikasi ke produksi.

Setelah mengikuti instruksi sebelumnya, aplikasi disebarkan ke Azure tetapi belum berfungsi. Sertifikat yang digunakan oleh aplikasi harus dikonfigurasi di portal Azure. Temukan thumbprint untuk sertifikat dan ikuti langkah-langkah yang dijelaskan dalam Memuat sertifikat Anda.

Meskipun langkah-langkah ini menyebutkan SSL, ada bagian Sertifikat privat di portal Azure tempat Anda dapat mengunggah sertifikat yang disediakan untuk digunakan dengan aplikasi.

Setelah mengonfigurasi aplikasi dan pengaturan aplikasi di portal Azure, mulai ulang aplikasi di portal.

Opsi konfigurasi lainnya

Dukungan untuk otorisasi API dibangun di atas IdentityServer dengan serangkaian konvensi, nilai default, dan penyempurnaan untuk menyederhanakan pengalaman untuk SPAs. Tidak perlu dikatakan, kekuatan Identitypenuh Server tersedia di belakang layar jika integrasi ASP.NET Core tidak mencakup skenario Anda. Dukungan ASP.NET Core difokuskan pada aplikasi "pihak pertama", tempat semua aplikasi dibuat dan disebarkan oleh organisasi kami. Dengan demikian, dukungan tidak ditawarkan untuk hal-hal seperti persetujuan atau federasi. Untuk skenario tersebut, gunakan IdentityServer dan ikuti dokumentasinya.

Profil aplikasi

Profil aplikasi adalah konfigurasi yang telah ditentukan sebelumnya untuk aplikasi yang lebih menentukan parameternya. Saat ini, profil berikut didukung:

  • IdentityServerSPA: Mewakili SPA yang dihosting Identitybersama Server sebagai satu unit.
    • Default redirect_uri ke /authentication/login-callback.
    • Default post_logout_redirect_uri ke /authentication/logout-callback.
    • Kumpulan cakupan mencakup openid, , profiledan setiap cakupan yang ditentukan untuk API di aplikasi.
    • Kumpulan jenis respons OIDC yang diizinkan adalah id_token token atau masing-masing secara individual (id_token, token).
    • Mode respons yang diizinkan adalah fragment.
  • SPA: Mewakili SPA yang tidak dihosting dengan IdentityServer.
    • Kumpulan cakupan mencakup openid, , profiledan setiap cakupan yang ditentukan untuk API di aplikasi.
    • Kumpulan jenis respons OIDC yang diizinkan adalah id_token token atau masing-masing secara individual (id_token, token).
    • Mode respons yang diizinkan adalah fragment.
  • IdentityServerJwt: Mewakili API yang dihosting bersama dengan IdentityServer.
    • Aplikasi ini dikonfigurasi untuk memiliki satu cakupan yang default ke nama aplikasi.
  • API: Mewakili API yang tidak dihosting dengan IdentityServer.
    • Aplikasi ini dikonfigurasi untuk memiliki satu cakupan yang default ke nama aplikasi.

Konfigurasi melalui AppSettings

Konfigurasikan aplikasi melalui sistem konfigurasi dengan menambahkannya ke daftar Clients atau Resources.

Konfigurasikan setiap klien redirect_uri dan post_logout_redirect_uri properti, seperti yang ditunjukkan dalam contoh berikut:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

Saat mengonfigurasi sumber daya, Anda dapat mengonfigurasi cakupan untuk sumber daya seperti yang ditunjukkan di bawah ini:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Konfigurasi melalui kode

Anda juga dapat mengonfigurasi klien dan sumber daya melalui kode menggunakan kelebihan beban AddApiAuthorization yang mengambil tindakan untuk mengonfigurasi opsi.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Sumber Daya Tambahan:

Templat ASP.NET Core 3.1 dan yang lebih baru menawarkan autentikasi di Aplikasi Halaman Tunggal (SPAs) menggunakan dukungan untuk otorisasi API. ASP.NET Core Identity untuk mengautentikasi dan menyimpan pengguna dikombinasikan dengan IdentityServer untuk menerapkan Koneksi OpenID.

Parameter autentikasi ditambahkan ke templat proyek Angular dan React yang mirip dengan parameter autentikasi di templat proyek Aplikasi Web (Model-View-Controller) (MVC) dan Aplikasi Web (Razor Halaman). Nilai parameter yang diizinkan adalah Tidak Ada dan Individual. Templat proyek React.js dan Redux saat ini tidak mendukung parameter autentikasi.

Membuat aplikasi dengan dukungan otorisasi API

Autentikasi dan otorisasi pengguna dapat digunakan dengan Angular dan React SPAs. Buka shell perintah, dan jalankan perintah berikut:

Sudut:

dotnet new angular -o <output_directory_name> 

React:

dotnet new react -o <output_directory_name> -au Individual

Perintah sebelumnya membuat aplikasi ASP.NET Core dengan direktori ClientApp yang berisi SPA.

Deskripsi umum komponen ASP.NET Core aplikasi

Bagian berikut menjelaskan penambahan ke proyek saat dukungan autentikasi disertakan:

Startup kelas

Contoh kode berikut mengandalkan Microsoft.AspNetCore.ApiAuthorization.IdentityPaket NuGet Server . Contoh mengonfigurasi autentikasi dan otorisasi API menggunakan AddApiAuthorization metode ekstensi dan AddIdentityServerJwt . Proyek yang menggunakan templat proyek React atau Angular SPA dengan autentikasi menyertakan referensi ke paket ini.

Kelas Startup memiliki penambahan berikut:

  • Startup.ConfigureServices Di dalam metode :

    • Identity dengan UI default:

      services.AddDbContext<ApplicationDbContext>(options =>
          options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
      
      services.AddDefaultIdentity<ApplicationUser>()
          .AddEntityFrameworkStores<ApplicationDbContext>();
      
    • IdentityServer dengan metode pembantu Identitytambahan AddApiAuthorization yang menyiapkan beberapa konvensi ASP.NET Core default di atas Server:

      services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
      
    • Autentikasi dengan metode pembantu tambahan AddIdentityServerJwt yang mengonfigurasi aplikasi untuk memvalidasi token JWT yang diproduksi oleh IdentityServer:

      services.AddAuthentication()
          .AddIdentityServerJwt();
      
  • Startup.Configure Di dalam metode :

    • Middleware autentikasi yang bertanggung jawab untuk memvalidasi kredensial permintaan dan mengatur pengguna pada konteks permintaan:

      app.UseAuthentication();
      
    • IdentityMiddleware Server yang mengekspos titik akhir Koneksi OpenID:

      app.UseIdentityServer();
      

Azure App Service di Linux

Untuk penyebaran Azure App Service di Linux, tentukan penerbit secara eksplisit di Startup.ConfigureServices:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

Dalam kode sebelumnya, {AUTHORITY} tempat penampung adalah Authority untuk digunakan saat melakukan panggilan Koneksi OpenID.

Contoh:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Metode pembantu Identityini mengonfigurasi Server untuk menggunakan konfigurasi kami yang didukung. IdentityServer adalah kerangka kerja yang kuat dan dapat diperluas untuk menangani masalah keamanan aplikasi. Pada saat yang sama, yang mengekspos kompleksitas yang tidak perlu untuk skenario yang paling umum. Akibatnya, serangkaian konvensi dan opsi konfigurasi disediakan untuk Anda yang dianggap sebagai titik awal yang baik. Setelah autentikasi Anda perlu berubah, kekuatan Identitypenuh Server masih tersedia untuk menyesuaikan autentikasi agar sesuai dengan kebutuhan Anda.

AddIdentityServerJwt

Metode pembantu ini mengonfigurasi skema kebijakan untuk aplikasi sebagai penangan autentikasi default. Kebijakan dikonfigurasi untuk memungkinkan Identity menangani semua permintaan yang dirutekan ke subpath apa pun di Identity ruang URL "/Identity". Menangani JwtBearerHandler semua permintaan lainnya. Selain itu, metode ini mendaftarkan <<ApplicationName>>API sumber daya API dengan IdentityServer dengan cakupan <<ApplicationName>>API default dan mengonfigurasi middleware token Pembawa JWT untuk memvalidasi token yang dikeluarkan oleh IdentityServer untuk aplikasi.

WeatherForecastController

Dalam file, perhatikan [Authorize] atribut yang diterapkan ke kelas yang menunjukkan bahwa pengguna perlu diotorisasi berdasarkan kebijakan default untuk mengakses sumber daya. Kebijakan otorisasi default kebetulan dikonfigurasi untuk menggunakan skema autentikasi default, yang disiapkan oleh AddIdentityServerJwt ke skema kebijakan yang disebutkan di atas, menjadikan JwtBearerHandler dikonfigurasi oleh metode pembantu tersebut sebagai handler default untuk permintaan ke aplikasi.

ApplicationDbContext

Dalam file, perhatikan bahwa hal yang sama DbContext digunakan dengan Identity pengecualian bahwa ia memperluas ApiAuthorizationDbContext (kelas yang lebih turunan dari IdentityDbContext) untuk menyertakan skema untuk IdentityServer.

Untuk mendapatkan kontrol penuh atas skema database, warisi dari salah satu kelas yang tersedia IdentityDbContext dan konfigurasikan konteks untuk menyertakan Identity skema dengan memanggil builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value)OnModelCreating metode .

OidcConfigurationController

Dalam file, perhatikan titik akhir yang disediakan untuk melayani parameter OIDC yang perlu digunakan klien.

appsettings.json

appsettings.json Dalam file akar proyek, ada bagian baru IdentityServer yang menjelaskan daftar klien yang dikonfigurasi. Dalam contoh berikut, ada satu klien. Nama klien sesuai dengan nama aplikasi dan dipetakan berdasarkan konvensi ke parameter OAuth ClientId . Profil menunjukkan jenis aplikasi yang sedang dikonfigurasi. Ini digunakan secara internal untuk mendorong konvensi yang menyederhanakan proses konfigurasi untuk server. Ada beberapa profil yang tersedia, seperti yang dijelaskan di bagian Profil aplikasi.

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

appsettings.Development.json Dalam file akar proyek, ada IdentityServer bagian yang menjelaskan kunci yang digunakan untuk menandatangani token. Saat menyebarkan ke produksi, kunci perlu disediakan dan disebarkan bersama aplikasi, seperti yang dijelaskan di bagian Sebarkan ke produksi .

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Deskripsi umum aplikasi Angular

Dukungan autentikasi dan otorisasi API dalam templat Angular berada dalam modul Angularnya sendiri di direktori ClientApp/src/api-authorization . Modul ini terdiri dari elemen-elemen berikut:

  • 3 komponen:
    • login.component.ts: Menangani alur masuk aplikasi.
    • logout.component.ts: Menangani alur keluar aplikasi.
    • login-menu.component.ts: Widget yang menampilkan salah satu set tautan berikut:
      • Manajemen profil pengguna dan tautan keluar saat pengguna diautentikasi.
      • Tautan pendaftaran dan masuk saat pengguna tidak diautentikasi.
  • Penjaga AuthorizeGuard rute yang dapat ditambahkan ke rute dan mengharuskan pengguna untuk diautentikasi sebelum mengunjungi rute.
  • Pencegat AuthorizeInterceptor HTTP yang melampirkan token akses ke permintaan HTTP keluar yang menargetkan API saat pengguna diautentikasi.
  • Layanan AuthorizeService yang menangani detail tingkat bawah proses autentikasi dan mengekspos informasi tentang pengguna yang diautentikasi ke aplikasi lainnya untuk dikonsumsi.
  • Modul Angular yang menentukan rute yang terkait dengan bagian autentikasi aplikasi. Ini mengekspos komponen menu login, pencegat, penjaga, dan layanan untuk dikonsumsi dari aplikasi lainnya.

Deskripsi umum aplikasi React

Dukungan untuk autentikasi dan otorisasi API di templat React berada di direktori ClientApp/src/components/api-authorization . Ini terdiri dari elemen-elemen berikut:

  • 4 komponen:
    • Login.js: Menangani alur masuk aplikasi.
    • Logout.js: Menangani alur keluar aplikasi.
    • LoginMenu.js: Widget yang menampilkan salah satu set tautan berikut:
      • Manajemen profil pengguna dan tautan keluar saat pengguna diautentikasi.
      • Tautan pendaftaran dan masuk saat pengguna tidak diautentikasi.
    • AuthorizeRoute.js: Komponen rute yang mengharuskan pengguna diautentikasi sebelum merender komponen yang ditunjukkan dalam Component parameter .
  • Instans kelas AuthorizeService yang diekspor authService yang menangani detail tingkat bawah dari proses autentikasi dan mengekspos informasi tentang pengguna yang diautentikasi ke aplikasi lainnya untuk dikonsumsi.

Sekarang setelah Anda melihat komponen utama solusi, Anda dapat melihat skenario individual yang lebih dalam untuk aplikasi.

Memerlukan otorisasi pada API baru

Secara default, sistem dikonfigurasi untuk dengan mudah memerlukan otorisasi untuk API baru. Untuk melakukannya, buat pengontrol baru dan tambahkan [Authorize] atribut ke kelas pengontrol atau ke tindakan apa pun dalam pengontrol.

Menyesuaikan handler autentikasi API

Untuk menyesuaikan konfigurasi handler JWT API, konfigurasikan instansnya JwtBearerOptions :

services.AddAuthentication()
    .AddIdentityServerJwt();

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Handler JWT API meningkatkan peristiwa yang memungkinkan kontrol atas proses autentikasi menggunakan JwtBearerEvents. Untuk memberikan dukungan untuk otorisasi API, AddIdentityServerJwt daftarkan penanganan aktivitasnya sendiri.

Untuk menyesuaikan penanganan peristiwa, bungkus penanganan aktivitas yang ada dengan logika tambahan sesuai kebutuhan. Contohnya:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

Dalam kode sebelumnya, penanganan OnTokenValidated aktivitas diganti dengan implementasi kustom. Implementasi ini:

  1. Memanggil implementasi asli yang disediakan oleh dukungan otorisasi API.
  2. Jalankan logika kustomnya sendiri.

Melindungi rute sisi klien (Angular)

Melindungi rute sisi klien dilakukan dengan menambahkan penjaga otorisasi ke daftar penjaga yang akan dijalankan saat mengonfigurasi rute. Sebagai contoh, Anda dapat melihat bagaimana rute dikonfigurasi fetch-data dalam modul Angular aplikasi utama:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Penting untuk disebutkan bahwa melindungi rute tidak melindungi titik akhir aktual (yang masih memerlukan atribut yang [Authorize] diterapkan padanya) tetapi hanya mencegah pengguna menavigasi ke rute sisi klien yang diberikan saat tidak diautentikasi.

Mengautentikasi permintaan API (Angular)

Mengautentikasi permintaan ke API yang dihosting bersama aplikasi dilakukan secara otomatis melalui penggunaan pencegat klien HTTP yang ditentukan oleh aplikasi.

Melindungi rute sisi klien (React)

Lindungi rute sisi klien dengan menggunakan AuthorizeRoute komponen alih-alih komponen biasa Route . Misalnya, perhatikan bagaimana rute dikonfigurasi fetch-data dalam App komponen:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Melindungi rute:

  • Tidak melindungi titik akhir aktual (yang masih memerlukan atribut yang [Authorize] diterapkan padanya).
  • Hanya mencegah pengguna menavigasi ke rute sisi klien yang diberikan saat tidak diautentikasi.

Mengautentikasi permintaan API (React)

Mengautentikasi permintaan dengan React dilakukan dengan terlebih dahulu mengimpor authService instans dari AuthorizeService. Token akses diambil dari authService dan dilampirkan ke permintaan seperti yang ditunjukkan di bawah ini. Dalam komponen React, pekerjaan ini biasanya dilakukan dalam componentDidMount metode siklus hidup atau sebagai hasil dari beberapa interaksi pengguna.

Mengimpor ke authService dalam komponen

import authService from './api-authorization/AuthorizeService'

Mengambil dan melampirkan token akses ke respons

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Menyebarkan ke produksi

Untuk menyebarkan aplikasi ke produksi, sumber daya berikut perlu disediakan:

  • Database untuk menyimpan Identity akun pengguna dan pemberian IdentityServer.
  • Sertifikat produksi yang digunakan untuk menandatangani token.
    • Tidak ada persyaratan khusus untuk sertifikat ini; dapat berupa sertifikat yang ditandatangani sendiri atau sertifikat yang disediakan melalui otoritas CA.
    • Ini dapat dihasilkan melalui alat standar seperti PowerShell atau OpenSSL.
    • Ini dapat diinstal ke penyimpanan sertifikat pada komputer target atau disebarkan sebagai file .pfx dengan kata sandi yang kuat.

Contoh: Menyebarkan ke penyedia hosting web non-Azure

Di panel hosting web Anda, buat atau muat sertifikat Anda. Kemudian dalam file aplikasi appsettings.json , ubah bagian IdentityServer untuk menyertakan detail utama. Contohnya:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

Dalam contoh sebelumnya:

  • StoreName mewakili nama penyimpanan sertifikat tempat sertifikat disimpan. Dalam hal ini, menunjuk ke penyimpanan hosting web.
  • StoreLocation mewakili tempat memuat sertifikat dari (CurrentUser dalam hal ini).
  • Name sesuai dengan subjek khusus untuk sertifikat.

Contoh: Menyebarkan ke Azure App Service

Bagian ini menjelaskan penyebaran aplikasi ke Azure App Service menggunakan sertifikat yang disimpan di penyimpanan sertifikat. Untuk memodifikasi aplikasi untuk memuat sertifikat dari penyimpanan sertifikat, paket layanan tingkat Standar atau lebih baik diperlukan saat Anda mengonfigurasi aplikasi di portal Azure di langkah selanjutnya.

Dalam file aplikasi appsettings.json , ubah bagian IdentityServer untuk menyertakan detail utama:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Nama penyimpanan mewakili nama penyimpanan sertifikat tempat sertifikat disimpan. Dalam hal ini, ini menunjuk ke penyimpanan pengguna pribadi.
  • Lokasi penyimpanan mewakili tempat memuat sertifikat dari (CurrentUser atau LocalMachine).
  • Properti nama pada sertifikat sesuai dengan subjek khusus untuk sertifikat.

Untuk menyebarkan ke Azure App Service, ikuti langkah-langkah dalam Menyebarkan aplikasi ke Azure, yang menjelaskan cara membuat sumber daya Azure yang diperlukan dan menyebarkan aplikasi ke produksi.

Setelah mengikuti instruksi sebelumnya, aplikasi disebarkan ke Azure tetapi belum berfungsi. Sertifikat yang digunakan oleh aplikasi harus dikonfigurasi di portal Azure. Temukan thumbprint untuk sertifikat dan ikuti langkah-langkah yang dijelaskan dalam Memuat sertifikat Anda.

Meskipun langkah-langkah ini menyebutkan SSL, ada bagian Sertifikat privat di portal Azure tempat Anda dapat mengunggah sertifikat yang disediakan untuk digunakan dengan aplikasi.

Setelah mengonfigurasi aplikasi dan pengaturan aplikasi di portal Azure, mulai ulang aplikasi di portal.

Opsi konfigurasi lainnya

Dukungan untuk otorisasi API dibangun di atas IdentityServer dengan serangkaian konvensi, nilai default, dan penyempurnaan untuk menyederhanakan pengalaman untuk SPAs. Tidak perlu dikatakan, kekuatan Identitypenuh Server tersedia di belakang layar jika integrasi ASP.NET Core tidak mencakup skenario Anda. Dukungan ASP.NET Core difokuskan pada aplikasi "pihak pertama", tempat semua aplikasi dibuat dan disebarkan oleh organisasi kami. Dengan demikian, dukungan tidak ditawarkan untuk hal-hal seperti persetujuan atau federasi. Untuk skenario tersebut, gunakan IdentityServer dan ikuti dokumentasinya.

Profil aplikasi

Profil aplikasi adalah konfigurasi yang telah ditentukan sebelumnya untuk aplikasi yang lebih menentukan parameternya. Saat ini, profil berikut didukung:

  • IdentityServerSPA: Mewakili SPA yang dihosting Identitybersama Server sebagai satu unit.
    • Default redirect_uri ke /authentication/login-callback.
    • Default post_logout_redirect_uri ke /authentication/logout-callback.
    • Kumpulan cakupan mencakup openid, , profiledan setiap cakupan yang ditentukan untuk API di aplikasi.
    • Kumpulan jenis respons OIDC yang diizinkan adalah id_token token atau masing-masing secara individual (id_token, token).
    • Mode respons yang diizinkan adalah fragment.
  • SPA: Mewakili SPA yang tidak dihosting dengan IdentityServer.
    • Kumpulan cakupan mencakup openid, , profiledan setiap cakupan yang ditentukan untuk API di aplikasi.
    • Kumpulan jenis respons OIDC yang diizinkan adalah id_token token atau masing-masing secara individual (id_token, token).
    • Mode respons yang diizinkan adalah fragment.
  • IdentityServerJwt: Mewakili API yang dihosting bersama dengan IdentityServer.
    • Aplikasi ini dikonfigurasi untuk memiliki satu cakupan yang default ke nama aplikasi.
  • API: Mewakili API yang tidak dihosting dengan IdentityServer.
    • Aplikasi ini dikonfigurasi untuk memiliki satu cakupan yang default ke nama aplikasi.

Konfigurasi melalui AppSettings

Konfigurasikan aplikasi melalui sistem konfigurasi dengan menambahkannya ke daftar Clients atau Resources.

Konfigurasikan setiap klien redirect_uri dan post_logout_redirect_uri properti, seperti yang ditunjukkan dalam contoh berikut:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

Saat mengonfigurasi sumber daya, Anda dapat mengonfigurasi cakupan untuk sumber daya seperti yang ditunjukkan di bawah ini:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Konfigurasi melalui kode

Anda juga dapat mengonfigurasi klien dan sumber daya melalui kode menggunakan kelebihan beban AddApiAuthorization yang mengambil tindakan untuk mengonfigurasi opsi.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Sumber Daya Tambahan: