之前有說到ASP.NET Core Identity 使用的是基於Claim 的驗證,其實ASP.NET Core Identity 有不同類型的授權方式,最簡單的登入授權、角色授權、Claim 授權,但上述幾種都是以一種方式實現:原則授權(Policy-based authorization)。
所謂的原則授權就是自定義一種Policy,只要滿足 Policy 定義的條件就能得到授權,不論條件是登入者是哪個 User、必須有某個Role、某個Claim、還是同時有Role 跟Claim等等。
一開始可能很難懂,筆者也是花了一段時間才理解,Claim 對應的是一組資訊如new Claim("Age", "18"),policy 則相當於規定如某間酒吧規定使用者的年齡必須大於 18 歲才能進入,之前說過 Role 就是類型為 Role 的 Claim,所以也是一樣的道理。
而在ASP.NET Core 定義 Policy 也不難,只要在Program.cs定義即可,下方的程式定義了一個 Policy 名為"IsAdmin",這個 Policy 指定需要有"ManageRole"這個 Claim 才能通過授權。
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("IsAdmin", policy => { policy.RequireClaim("ManageRole"); });
});
在套用先前進入 User 編輯 Claim 的頁面,讓目前登入者test@gmail.com持有所有 Claim,否則套用後就看不到這些頁面了。另外也編輯user@gmail.com不過不勾選任何 Claim 直接儲存,方便待會測試。

在應用上也跟 Role 一樣,在[AuthorzieAttribute]後面放入 Policy 這個參數即可,以UserManagement.razor為例。
@page "/UserManagement/UserList" @attribute [Authorize(Policy = "IsAdmin")] …
NavMenu.razor也產生一個新的<AuthorizeView> Component,變數套用 Policy。
<AuthorizeView Policy="IsAdmin">
<Authorized>
<li class="nav-item px-3">
<NavLink
class="nav-link"
href="UserManagement/UserList"
Match="NavLinkMatch.All"
>
<span class="bi bi-people h4 p-2 mb-0" aria-hidden="true"></span> Users
</NavLink>
</li>
</Authorized>
</AuthorizeView>
但這時若以user@gmail.com登入,卻可以看到 User 管理頁面,明明ManageUser的值為 false,這是因為 Policy "IsAdmin" 只有要求"ManageRole"這個 ClaimType,通常系統不會這樣授權,而是會同時比對 ClaimType 跟 ClaimValue,所以把 Policy "IsAdmin" 改完善一點,指定 "IsAdmin" 的 ClaimValue 必須為 "true",這樣就完成了簡易的 Policy 授權了。


另外要注意的是 ASP.NET Core 對 ClaimType 的處理是不分大小寫,但對 ClaimValue 卻是大小寫分明,以 Policy "IsAdmin"為例,ClaimType 可以是"manageUser"或是"manageuser",ClaimValue 則必須為 "true"。
引用:
- Policy-based Authorization in ASP.NET Core – A Deep Dive
- Claim type and claim value in claims policy based authorization in asp net core
- Simple authorization in ASP.NET Core
註:本文程式碼透過 .NET 6 + Visual Studio 2022 重構,可點選原文連結與重構後程式碼比較學習,謝謝閱讀,支援原作者