Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam artikel ini, Anda menerapkan otorisasi di API web ASP.NET Core menggunakan Microsoft. Identity.Web. Anda akan memvalidasi cakupan (izin yang didelegasikan) dan izin aplikasi (izin aplikasi) untuk mengontrol akses ke sumber daya yang dilindungi. Contohnya menggunakan Microsoft Entra ID sebagai penyedia identitas.
Memahami konsep otorisasi
Bagian ini mencakup perbedaan utama antara autentikasi dan otorisasi, dan menjelaskan apa yang Microsoft. Identity.Web memvalidasi dalam token akses.
Autentikasi vs otorisasi
| Konsep | Kegunaan | Result |
|---|---|---|
| Authentication | Verifikasi identitas | 401 Tidak Sah jika gagal |
| Otorisasi | Memverifikasi izin | 403 Dilarang jika tidak memadai |
Apa yang divalidasi
Saat API web menerima token akses, Microsoft. Identity.Web memvalidasi:
- Tanda tangan token - Apakah dari otoritas tepercaya?
- Audiens token - Apakah ditujukan untuk API ini?
- Kedaluwarsa token - Apakah masih valid?
- Cakupan/Peran - Apakah aplikasi klien dan subjek (pengguna) memiliki izin yang tepat?
Panduan ini berfokus pada #4 - memvalidasi cakupan dan izin aplikasi.
Cakupan (izin yang didelegasikan)
Cakupan berlaku saat pengguna mendelegasikan izin ke aplikasi untuk bertindak atas nama mereka (misalnya, API web yang disebut atas nama pengguna yang masuk).
| Detail | Nilai |
|---|---|
| Klaim token |
scp atau scope (aplikasi klien); roles (pengguna) |
| Contoh nilai |
"access_as_user", "User.Read", "Files.ReadWrite" |
Izin aplikasi (izin aplikasi)
Izin aplikasi berlaku saat aplikasi memanggil API web dengan sendirinya tanpa konteks pengguna, seperti daemon atau layanan latar belakang menggunakan kredensial klien.
| Detail | Nilai |
|---|---|
| Klaim token | roles |
| Contoh nilai |
"Mail.Read.All", "User.Read.All" |
Memvalidasi cakupan dengan RequiredScope
Atribut RequiredScope memeriksa bahwa token akses berisi setidaknya salah satu cakupan yang ditentukan. Gunakan atribut ini saat API Anda hanya melayani permintaan yang didelegasikan pengguna.
Menyiapkan validasi cakupan
Ikuti langkah-langkah ini untuk mengaktifkan validasi cakupan di API Anda.
1. Aktifkan otorisasi di API Anda:
Tambahkan layanan autentikasi dan otorisasi ke alur aplikasi Anda:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(); // Required for authorization
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization(); // Must be after UseAuthentication
app.MapControllers();
app.Run();
2. Lindungi pengontrol atau tindakan:
Terapkan [Authorize] atribut dan [RequiredScope] ke pengontrol atau tindakan individual Anda:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Only accessible if token has "access_as_user" scope
return Ok(new[] { "Todo 1", "Todo 2" });
}
}
Menerapkan pola ruang lingkup
Pilih pola yang paling sesuai dengan cara Anda mengelola cakupan dalam aplikasi Anda.
Pola 1: Cakupan yang dikodekan secara permanen
Gunakan pola ini saat cakupan tetap dan diketahui pada waktu pengembangan.
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
// All actions require "access_as_user" scope
}
Untuk menerima salah satu dari beberapa cakupan, cantumkan sebagai parameter:
[Authorize]
[RequiredScope("read", "write", "admin")]
public class TodoListController : ControllerBase
{
// Token must have "read" OR "write" OR "admin"
}
Pola 2: Lingkup dari konfigurasi
Gunakan pola ini ketika cakupan harus dapat dikonfigurasi per lingkungan. Tentukan cakupan dalam file konfigurasi Anda:
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user read write"
}
}
Referensikan kunci konfigurasi di pengontrol Anda:
[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : ControllerBase
{
// Scopes read from configuration
}
Pendekatan ini memungkinkan Anda mengubah cakupan tanpa kompilasi ulang.
Pola 3: Cakupan tingkat tindakan
Gunakan pola ini ketika tindakan yang berbeda memerlukan izin yang berbeda. Terapkan [RequiredScope] ke metode tindakan individual:
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[RequiredScope("read")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[RequiredScope("write")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
// Only tokens with "write" scope can create
return CreatedAtAction(nameof(GetTodos), todo);
}
[HttpDelete("{id}")]
[RequiredScope("admin")]
public IActionResult DeleteTodo(int id)
{
// Only tokens with "admin" scope can delete
return NoContent();
}
}
Memahami alur validasi
Ketika permintaan tiba, middleware memprosesnya dalam urutan berikut:
- ASP.NET Core middleware autentikasi memvalidasi token
-
RequiredScopepemeriksaan atribut untuk klaimscpatauscope - Jika token berisi setidaknya satu cakupan yang cocok, permintaan akan dilanjutkan.
- Jika tidak ada cakupan yang cocok yang ditemukan, API mengembalikan respons Terlarang 403.
Contoh berikut menunjukkan respons kesalahan umum:
{
"error": "insufficient_scope",
"error_description": "The token does not have the required scope 'access_as_user'."
}
Memvalidasi izin aplikasi dengan RequiredScopeOrAppPermission
Atribut RequiredScopeOrAppPermission memvalidasi cakupan (didelegasikan) atau izin aplikasi (aplikasi). Gunakan atribut ini saat API Anda melayani aplikasi yang didelegasikan pengguna dan aplikasi daemon/layanan dari titik akhir yang sama.
Jika API Anda hanya melayani permintaan yang didelegasikan pengguna, gunakan RequiredScope sebagai gantinya.
Menyiapkan cakupan atau validasi izin aplikasi
Terapkan atribut untuk menerima salah satu jenis token:
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScopeOrAppPermission(
AcceptedScope = new[] { "access_as_user" },
AcceptedAppPermission = new[] { "TodoList.ReadWrite.All" }
)]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Accessible with EITHER:
// - User-delegated token with "access_as_user" scope, OR
// - App-only token with "TodoList.ReadWrite.All" app permission
return Ok(todos);
}
}
Mengonfigurasi izin aplikasi dari pengaturan
Simpan cakupan dan izin aplikasi dalam konfigurasi untuk mengubahnya tanpa kompilasi ulang.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user",
"AppPermissions": "TodoList.ReadWrite.All TodoList.Admin"
}
}
Referensikan kunci konfigurasi di pengontrol Anda:
[Authorize]
[RequiredScopeOrAppPermission(
RequiredScopesConfigurationKey = "AzureAd:Scopes",
RequiredAppPermissionsConfigurationKey = "AzureAd:AppPermissions"
)]
public class TodoListController : ControllerBase
{
// Scopes and app permissions from configuration
}
Membandingkan klaim token yang berbeda
Tabel berikut menunjukkan perbedaan klaim antara token yang didelegasikan pengguna dan hanya aplikasi:
| Jenis Token | Tuntutan | Contoh Nilai |
|---|---|---|
| Didelegasikan pengguna |
scp atau scope |
"access_as_user User.Read" |
| Hanya aplikasi | roles |
["TodoList.ReadWrite.All"] |
Contoh berikut menunjukkan token yang didelegasikan pengguna:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"scp": "access_as_user",
"sub": "user-object-id",
...
}
Contoh berikut menunjukkan token khusus aplikasi:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"roles": ["TodoList.ReadWrite.All"],
"sub": "app-object-id",
...
}
Membuat kebijakan otorisasi
Untuk skenario otorisasi yang kompleks, gunakan kebijakan otorisasi ASP.NET Core. Kebijakan memungkinkan Anda mempusatkan aturan, menggabungkan beberapa persyaratan, dan menulis logika otorisasi yang dapat diuji.
| Keuntungan | Deskripsi |
|---|---|
| Logika terpusat | Tentukan aturan otorisasi sekali, gunakan kembali di mana saja |
| Komposabel | Menggabungkan beberapa persyaratan (ruang lingkup + klaim + logika khusus) |
| Dapat diuji | Lebih mudah untuk menyatukan logika otorisasi pengujian |
| Flexibel | Persyaratan kustom di luar validasi ruang lingkup |
Pola 1: Tentukan kebijakan dengan RequireScope
Tentukan kebijakan bernama yang memerlukan cakupan tertentu, lalu referensikan pada pengontrol Anda:
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("TodoReadPolicy", policyBuilder =>
{
policyBuilder.RequireScope("read", "access_as_user");
});
options.AddPolicy("TodoWritePolicy", policyBuilder =>
{
policyBuilder.RequireScope("write", "admin");
});
});
var app = builder.Build();
Terapkan kebijakan ke tindakan pengontrol:
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[Authorize(Policy = "TodoReadPolicy")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[Authorize(Policy = "TodoWritePolicy")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
return CreatedAtAction(nameof(GetTodos), todo);
}
}
Pola 2: Tentukan kebijakan dengan ScopeAuthorizationRequirement
Gunakan ScopeAuthorizationRequirement untuk persyaratan cakupan yang lebih eksplisit:
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CustomPolicy", policyBuilder =>
{
policyBuilder.AddRequirements(
new ScopeAuthorizationRequirement(new[] { "access_as_user" })
);
});
});
Pola 3: Mengatur kebijakan default
Tetapkan kebijakan default yang berlaku untuk semua [Authorize] atribut secara otomatis:
builder.Services.AddAuthorization(options =>
{
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireScope("access_as_user")
.Build();
options.DefaultPolicy = defaultPolicy;
});
Setiap [Authorize] atribut sekarang memerlukan access_as_user cakupan:
[Authorize] // Automatically requires "access_as_user" scope
public class TodoListController : ControllerBase
{
// All actions protected by default policy
}
Pola 4: Menggabungkan beberapa persyaratan
Gabungkan persyaratan cakupan, peran, dan autentikasi dalam satu kebijakan:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policyBuilder =>
{
policyBuilder.RequireScope("admin");
policyBuilder.RequireRole("Admin"); // Also check role claim
policyBuilder.RequireAuthenticatedUser();
});
});
Pola 5: Membangun kebijakan dari konfigurasi
Memuat cakupan dari konfigurasi untuk memastikan kebijakan tetap khusus untuk lingkungan tertentu.
var requiredScopes = builder.Configuration["AzureAd:Scopes"]?.Split(' ');
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ApiAccessPolicy", policyBuilder =>
{
if (requiredScopes != null)
{
policyBuilder.RequireScope(requiredScopes);
}
});
});
Memfilter permintaan menurut penyewa
Batasi akses API ke token dari penyewa Microsoft Entra tertentu. Ini berfungsi ketika API multi-penyewa Anda hanya boleh menerima permintaan dari penyewa pelanggan yang telah disetujui.
Membatasi akses ke penyewa yang diizinkan
Tentukan kebijakan yang memeriksa klaim ID penyewa terhadap daftar yang diizinkan:
builder.Services.AddAuthorization(options =>
{
string[] allowedTenants =
{
"14c2f153-90a7-4689-9db7-9543bf084dad", // Contoso tenant
"af8cc1a0-d2aa-4ca7-b829-00d361edb652", // Fabrikam tenant
"979f4440-75dc-4664-b2e1-2cafa0ac67d1" // Northwind tenant
};
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
// Apply to all endpoints by default
options.DefaultPolicy = options.GetPolicy("AllowedTenantsOnly");
});
Mengatur pemfilteran penyewa melalui pengaturan
Simpan ID tenant yang diizinkan dalam konfigurasi untuk mengelolanya tanpa perubahan kode.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "your-api-client-id",
"AllowedTenants": [
"14c2f153-90a7-4689-9db7-9543bf084dad",
"af8cc1a0-d2aa-4ca7-b829-00d361edb652"
]
}
}
Baca daftar penyewa dan buat kebijakan saat startup:
var allowedTenants = builder.Configuration.GetSection("AzureAd:AllowedTenants")
.Get<string[]>();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants ?? Array.Empty<string>()
);
});
});
Menggabungkan cakupan dengan pemfilteran penyewa
Buat kebijakan yang memerlukan cakupan yang valid dan penyewa yang disetujui:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("SecureApiAccess", policyBuilder =>
{
// Require specific scope
policyBuilder.RequireScope("access_as_user");
// AND require specific tenant
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
});
Ikuti praktik terbaik
Terapkan rekomendasi ini untuk membangun logika otorisasi yang aman dan dapat dipertahankan.
Yang Harus Dilakukan
1. Selalu pasangkan [Authorize] dengan validasi cakupan:
[Authorize] // Authentication
[RequiredScope("access_as_user")] // Authorization
public class MyController : ControllerBase { }
2. Gunakan konfigurasi untuk cakupan khusus lingkungan:
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
3. Terapkan hak istimewa paling sedikit:
[HttpGet]
[RequiredScope("read")] // Only read permission needed
[HttpPost]
[RequiredScope("write")] // Write permission for modifications
4. Gunakan kebijakan untuk otorisasi kompleks:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireScope("admin");
policy.RequireClaim("department", "IT");
});
});
5. Aktifkan respons kesalahan terperinci dalam pengembangan:
if (builder.Environment.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}
Hal-hal yang Tidak Boleh Dilakukan
1. Jangan lewati [Authorize] saat menggunakan RequiredScope:
// Wrong - RequiredScope won't work without [Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
// Correct
[Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
2. Jangan hardcode ID penyewa di lingkungan produksi:
// Wrong
policyBuilder.RequireClaim("tid", "14c2f153-90a7-4689-9db7-9543bf084dad");
// Better - use configuration
var tenants = Configuration.GetSection("AllowedTenants").Get<string[]>();
policyBuilder.RequireClaim("tid", tenants);
3. Jangan membingungkan cakupan dengan peran:
// Wrong - This checks roles claim, not scopes
[RequiredScope("Admin")] // "Admin" is typically a role, not a scope
// Correct
[RequiredScope("access_as_user")] // Scope
[Authorize(Roles = "Admin")] // Role
4. Jangan mengekspos informasi cakupan sensitif dalam pesan kesalahan produksi:
Konfigurasikan tingkat pengelogan yang sesuai dan penanganan kesalahan untuk lingkungan produksi.
Memecahkan masalah otorisasi
Gunakan panduan berikut untuk mendiagnosis masalah otorisasi umum.
403 Terlarang - cakupan hilang
Kesalahan: API mengembalikan 403 bahkan dengan token yang valid.
Diagnosis:
- Dekode token pada jwt.ms.
- Periksa klaim
scpatauscope. - Verifikasi bahwa nilai cocok dengan atribut Anda
RequiredScope.
Solution:
- Pastikan aplikasi klien meminta cakupan yang benar saat memperoleh token.
- Verifikasi ruang lingkup yang diekspos dalam pendaftaran aplikasi API di Microsoft Entra.
- Berikan persetujuan admin jika diperlukan.
RequiredScope tidak berfungsi
Gejala: Atribut tampaknya diabaikan.
Check:
- Apakah Anda menambahkan
[Authorize]atribut? - Apakah
app.UseAuthorization()dipanggil setelahapp.UseAuthentication()? - Apakah
services.AddAuthorization()terdaftar?
Kunci konfigurasi tidak ditemukan
Kesalahan: Validasi cakupan gagal secara diam-diam.
Check:
{
"AzureAd": {
"Scopes": "access_as_user" // Matches RequiredScopesConfigurationKey
}
}
Pastikan jalur konfigurasi cocok dengan tepat.