如何使用Asp.Net Core实现基于权限的访问控制

我正在尝试使用aspnet核心实现基于权限的访问控制。 为了动态管理用户角色和权限(create_product,delete_product等),它们存储在数据库中。 数据模型类似于http://sofzh.miximages.com/c%23/CHMPE.png

在aspnet核心之前(在MVC 5中)我使用如下的自定义AuthorizeAttribute来处理问题:

 public class CustomAuthorizeAttribute : AuthorizeAttribute { private readonly string _permissionName { get; set; } [Inject] public IAccessControlService _accessControlService { get; set; } public CustomAuthorizeAttribute(string permissionName = "") { _permissionName = permissionName; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); var user = _accessControlService.GetUser(); if (PermissionName != "" && !user.HasPermission(_permissionName)) { // set error result filterContext.HttpContext.Response.StatusCode = 403; return; } filterContext.HttpContext.Items["CUSTOM_USER"] = user; } } 

然后我在下面的动作方法中使用它:

 [HttpGet] [CustomAuthorize(PermissionEnum.PERSON_LIST)] public ActionResult Index(PersonListQuery query){ } 

另外,我在视图中使用HttpContext.Items [“CUSTOM_USER”]来显示或隐藏html部分:

 @if (CurrentUser.HasPermission("")) { } 

当我决定切换aspnet核心时,我的所有计划都失败了。 因为AuthorizeAttribute没有虚拟的OnAuthorization方法。 我尝试了一些解决问题的方法。 这些是:

  • 使用新的基于策略的授权(我认为它不适合我的scenerio)

  • 使用自定义AuthorizeAttributeAuthorizationFilter (我读过这篇文章https://stackoverflow.com/a/35863514/5426333但我无法正确更改)

  • 使用自定义中间件(如何获取当前操作的AuthorizeAttribute ?)

  • 使用ActionFilter(出于安全目的,它是否正确?)

我无法确定哪种方式最适合我的场景以及如何实现它。

第一个问题 :MVC5实施不好吗?

第二个问题 :你有任何建议实施aspnet核心吗?

根据评论,这里有一个关于如何使用基于策略的授权的示例:

 public class PermissionRequirement : IAuthorizationRequirement { public PermissionRequirement(PermissionEnum permission) { Permission = permission; } public PermissionEnum Permission { get; } } public class PermissionHandler : AuthorizationHandler { private readonly IUserPermissionsRepository permissionRepository; public PermissionHandler(IUserPermissionsRepository permissionRepository) { if(permissionRepository == null) throw new ArgumentNullException(nameof(permissionRepository)); this.permissionRepository = permissionRepository; } protected override void Handle(AuthorizationContext context, PermissionRequirement requirement) { if(context.User == null) { // no user authorizedd. Alternatively call context.Fail() to ensure a failure // as another handler for this requirement may succeed return null; } bool hasPermission = permissionRepository.CheckPermissionForUser(context.User, requirement.Permission); if (hasPermission) { context.Succeed(requirement); } } } 

并在Startup类中注册它:

 services.AddAuthorization(options => { UserDbContext context = ...; foreach(var permission in context.Permissions) { // assuming .Permission is enum options.AddPolicy(permission.Permission.ToString(), policy => policy.Requirements.Add(new PermissionRequirement(permission.Permission))); } }); // Register it as scope, because it uses Repository that probably uses dbcontext services.AddScope(); 

最后在控制器中

 [HttpGet] [Authorize(Policy = PermissionEnum.PERSON_LIST.ToString())] public ActionResult Index(PersonListQuery query) { ... } 

此解决方案的优点是您还可以为需求提供多个处理程序,即如果第一个处理程序成功,第二个处理程序可以确定它是一个失败,您可以使用基于资源的授权 ,而不需要额外的努力。

基于策略的方法是ASP.NET核心团队执行此操作的首选方法。

来自blowdart :

我们不希望您编写自定义授权属性。 如果你需要这样做我们做错了什么。 相反,你应该写授权要求。

对于不需要为每个权限添加策略的解决方案,请参阅我对另一个问题的回答。

它允许您使用您希望的任何自定义属性来装饰控制器和操作,并在AuthorizationHandler中访问它们。

我有同样的要求,我已经完成了如下,它对我来说很好。 我正在使用.Net Core 2.0 Webapi

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class CheckAccessAttribute : AuthorizeAttribute, IAuthorizationFilter { private string[] _permission; public CheckAccessAttribute(params string[] permission) { _permission = permission; } public void OnAuthorization(AuthorizationFilterContext context) { var user = context.HttpContext.User; if (!user.Identity.IsAuthenticated) { return; } IRepository service = (IRepositoryWrapper)context.HttpContext.RequestServices.GetService(typeof(IRepository)); var success = service.CheckAccess(userName, _permission.ToList()); if (!success) { context.Result = JsonFormatter.GetErrorJsonObject(CommonResource.error_unauthorized, StatusCodeEnum.Forbidden); return; } return; } } 

在Controller中使用它如下所示

  [HttpPost] [CheckAccess(Permission.CreateGroup)] public JsonResult POST([FromBody]Group group) { // your code api code here. } 
Interesting Posts