之前有說到 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 也不難,只要在ConfigureServices()
定義即可,下方的程式定義了一個 Policy 名為"IsAdmin",這個 Policy 指定需要有"ManageRole"這個 Claim 才能通過授權。
public void ConfigureServices(IServiceCollection services)
{
…
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"。
Ref: Policy-based Authorization in ASP.NET Core – A Deep Dive
Ref: Claim type and claim value in claims policy based authorization in asp net core
Ref: Simple authorization in ASP.NET Core