在 ASP.NET Core 實作角色權限授權後,能夠在 Controller 或是 Action 上使用 Authorize 註解(Attribute) 綁定角色(Roles)或權限(Policy,應該翻譯為策略,但筆者覺得翻譯為權限似乎比較容易理解)
若使用 API JWT 登入,需要在 JWT 內包含權限和策略才可以通過 Authorize 的驗證
JWT 內容範例:
若權限數量眾多,則 JWT 就需要夾帶很多資料,且權限內容都被看光光(雖然 JWT 需要發行者簽章),那有沒有更好的方式?
有的,在筆者研究很久,使用中介軟體(Middleware) 怎麼都失敗之後,最後終於嘗試出來了,就是在 JwtBearerEvents 的 OnTokenValidated 事件中動態賦予角色和權限!
註:筆者在測試時發現如果「預設授權策略」(在每個 Controller 或 Action 上使用 AuthorizeAttribute 指定不會有問題)使用 IdentityConstants.ApplicationScheme 和 JwtBearerDefaults.AuthenticationScheme 等多個時,下面的方式會失效,目前還未能解決,如果有解決的方式,還請留言指點,感激不盡!
[Authorize(Roles = "Admin")] // 指定角色為 Admin 才可存取
[Authorize(Policy = "ProductEdit")] // 指定具有 ProductEdit 權限才可存取
public IActionResult Test1(){
// 省略
}
若使用 API JWT 登入,需要在 JWT 內包含權限和策略才可以通過 Authorize 的驗證
JWT 內容範例:
{
"sub": "1234567890",
"name": "Ruyut",
"iat": 1516239022,
"exp": 1516239122,
"roles": [
"Admin",
"User"
],
"policies": [
"ProductEdit"
]
}
若權限數量眾多,則 JWT 就需要夾帶很多資料,且權限內容都被看光光(雖然 JWT 需要發行者簽章),那有沒有更好的方式?
有的,在筆者研究很久,使用中介軟體(Middleware) 怎麼都失敗之後,最後終於嘗試出來了,就是在 JwtBearerEvents 的 OnTokenValidated 事件中動態賦予角色和權限!
註:筆者在測試時發現如果「預設授權策略」(在每個 Controller 或 Action 上使用 AuthorizeAttribute 指定不會有問題)使用 IdentityConstants.ApplicationScheme 和 JwtBearerDefaults.AuthenticationScheme 等多個時,下面的方式會失效,目前還未能解決,如果有解決的方式,還請留言指點,感激不盡!
builder.Services
.AddAuthentication(options => options.DefaultScheme = IdentityConstants.ApplicationScheme)
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents()
{
OnTokenValidated = async (context) =>
{
var userName = context.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var userManager = context.HttpContext.RequestServices.GetService<UserManager<User>>();
var roleManager = context.HttpContext.RequestServices.GetService<RoleManager<Role>>();
var user = await userManager.FindByNameAsync(userName);
if (user == null) return;
var roles = await userManager.GetRolesAsync(user);
foreach (var role in roles)
{
((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, role));
if (roleManager != null)
{
var roleObj = await roleManager.FindByNameAsync(role);
var permissions = await roleManager.GetClaimsAsync(roleObj);
foreach (var permission in permissions)
{
((ClaimsIdentity)context.Principal.Identity).AddClaim(permission);
}
}
}
},
};
});
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com