本文介绍了如何实现基于角色的访问控制与Asp.Net核心权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实现与ASPNET核心权限的访问控制。用于动态地管理用户角色和权限(create_product,delete_product等),它们被存储在数据库中。数据模型是如

I am trying to implement permission based access control with aspnet core. For dynamically managing user roles and permissions(create_product, delete_product etc.), they are stored in the database. Data Model is like http://i.stack.imgur.com/CHMPE.png

在ASPNET核心(MVC中的5)我使用自定义的 AuthorizeAttribute 象下面这样来处理这个问题:

Before aspnet core (in MVC 5) i was using custom AuthorizeAttribute like below to handle the issue:

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;
    }
}

然后我使用它的操作方法如下图所示:

Then i was using it in action method like below:

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

此外,我是使用HttpContext.Items [CUSTOM_USER]在视图中显示或隐藏的HTML部分:

Additionally, i was using HttpContext.Items["CUSTOM_USER"] in views to show or hide html part:

@if (CurrentUser.HasPermission("<Permission Name>"))
{

}

当我决定改用ASPNET核心,我所有的计划失败了。因为当时在 AuthorizeAttribute 无虚 OnAuthorization 方法。我尝试了一些方法来解决问题。这些都是如下:

When i decided to switch aspnet core, all my plan was failed. Because there was no virtual OnAuthorization method in the AuthorizeAttribute. I tried some ways to solve problem. Those are below:


  • 使用新的基于策略的授权,(我认为这是不适合
    我之情况)

  • Using new policy based authorization(i think it is not suitable formy scenerio)

使用自定义 AuthorizeAttribute AuthorizationFilter (我读到这
发布,但我不能改变它正常)

Using custom AuthorizeAttribute and AuthorizationFilter(i read thispost http://stackoverflow.com/a/35863514/5426333 but i couldn’t change it properly)

使用自定义的中间件(如何获得 AuthorizeAttribute 电流
行动?)

Using custom middleware(how to get AuthorizeAttribute of currentaction?)

使用ActionFilter(它是正确的,为了保密?)

Using ActionFilter(is it correct for security purpose?)

我不能决定哪种方式最适合我之情况以及如何实现它。

I couldn’t decide which way is the best for my scenerio and how to implement it.

第一个问题:是否MVC5执行不好的做法

First question: Is MVC5 implementation bad practice?

第二个问题:你有什么建议实施ASPNET核心

Second question: Do you have any suggest to implement aspnet core?

推荐答案

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

Based on the comments, here an example on how to use the policy based authorization:

public class PermissionRequirement : IAuthorizationRequirement
{
    public PermissionBasedRequirement(PermissionEnum permission)
    {
         Permission = permission;
    }

    public PermissionEnum Permission { get; }
}

public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
    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);
        }
    }
}

而在你的启动类进行注册:

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<IAuthorizationHandler, PermissionHandler>();

终于在控制器

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

这种解决方案的好处是,你也可以有多个处理程序的要求,也就是说,如果第一次成功,第二个处理程序可以判断这是一个失败,你可以用的的。

的基于策略的方法是preferred方式由ASP.NET核心团队去做。

The policy based approach is the preferred way to do it by the ASP.NET Core team.

通过:

我们不希望你编写自定义授权属性。如果你需要做的,我们已经做了一些错误。相反,你应该写授权要求。

这篇关于如何实现基于角色的访问控制与Asp.Net核心权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 14:14