[英]How can I implement Claims-Based Authorization with ASP.NET WebAPI without using Roles?
[英]Can asp.net core policies and claims handle resource/activity based authorization?
我正在研究asp.net核心以及新的安全策略和聲明功能。 剛剛看過它我看不出它比過去現有的授權屬性邏輯更好,在過去硬編碼的角色或用戶在控制器,方法等上進行裝飾。對我來說,問題剛剛從硬 - 將屬性編碼為硬編碼策略。
理想情況下,我想執行基於活動/資源的授權,其中一切都將由數據庫驅動。 每個活動或資源都將存儲在數據庫中,並且權限/角色將分配給該資源。
在研究這個主題時,我發現Stefan Wloch寫的這篇精彩文章幾乎涵蓋了我正在尋找的內容。
http://www.codeproject.com/Articles/1079552/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NE
所以我的問題是新的核心功能如何在更改允許訪問控制器中的控制器或方法的角色/權限時,如何阻止我們進行硬編碼和重新編譯? 我理解索賠如何用於存儲任何東西,但政策部分似乎容易改變,這使我們回到原點。 不要誤會我的意思,喜歡asp.net核心和所有重大變化,只是尋找有關如何處理授權的更多信息。
在實現您想要的內容時,至少需要考慮兩件事。 第一個是如何在數據庫中建模Controller-Action訪問,第二個是在asp.net核心身份中應用該設置。
第一個,依賴於應用程序本身的可能性太多,所以讓我們創建一個名為IActivityAccessService
的服務接口來封裝。 我們通過依賴注入使用該服務,以便我們需要的任何東西都可以注入它。
至於第二個,可以通過在基於策略的AuthorizationHandler
中自定義AuthorizationHandler
來實現。 第一步是在Startup.ConfigureServices
設置:
services.AddAuthorization(options =>
{
options.AddPolicy("ActivityAccess", policy => policy.Requirements.Add( new ActivityAccessRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ActivityAccessHandler>();
//inject the service also
services.AddScoped<IActivityAccessService, ActivityAccessService>();
//code below will be explained later
services.AddHttpContextAccessor();
接下來我們創建ActivityAccessHandler
:
public class ActivityAccessHandler : AuthorizationHandler<ActivityAccessRequirement>
{
readonly IActivityAccessService _ActivityAccessService;
public ActivityAccessHandler (IActivityAccessService r)
{
_ActivityAccessService = r;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext, ActivityAccessRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = (filterContext.RouteData.Values["area"] as string)?.ToLower();
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = (filterContext.RouteData.Values["id"] as string)?.ToLower();
if (_ActivityAccessService.IsAuthorize(area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
public class ActivityAccessRequirement : IAuthorizationRequirement
{
//since we handle the authorization in our service, we can leave this empty
}
由於我們可以在AuthorizationHandler
使用依賴注入,因此我們在這里注入IActivityAccessService
。
現在我們可以訪問所請求的資源,我們需要知道誰在請求它。 這可以通過注入IHttpContextAccessor
來完成。 因此在上面的代碼中添加了services.AddHttpContextAccessor()
,正是出於這個原因。
對於IActivityAccessService
,您可以執行以下操作:
public class ActivityAccessService : IActivityAccessService
{
readonly AppDbContext _context;
readonly IConfiguration _config;
readonly IHttpContextAccessor _accessor;
readonly UserManager<AppUser> _userManager;
public class ActivityAccessService(AppDbContext d, IConfiguration c, IHttpContextAccessor a, UserManager<AppUser> u)
{
_context = d;
_config = c;
_accessor = a;
_userManager = u;
}
public bool IsAuthorize(string area, string controller, string action, string id)
{
//get the user object from the ClaimPrincipals
var appUser = await _userManager.GetUserAsync(_accessor.HttpContext.User);
//get user roles if necessary
var userRoles = await _userManager.GetRolesAsync(appUser);
// all of needed data are available now, do the logic of authorization
return result;
}
}
請注意,上面IsAuthorize主體中的代碼就是一個例子。 雖然它可行,但人們可能會說這不是一個好習慣。 但由於IActivityAccessService
只是一個常見的簡單服務類,我們可以注入任何需要的東西,並以我們想要的任何方式修改IsAuthorize
方法簽名。 例如,我們可以只傳遞filterContext.RouteData
。
至於如何將其應用於控制器或動作:
[Authorize(Policy = "ActivityAccess")]
public ActionResult<IActionResult> GetResource(int resourceId)
{
return Resource;
}
希望這可以幫助
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.