如何使用 Asp.Net Core 实现基于权限的访问控制 [英] How to implement Permission Based Access Control with Asp.Net Core

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

问题描述

我正在尝试使用 aspnet 核心实现基于权限的访问控制.为了动态管理用户角色和权限(create_product、delete_product 等),它们存储在数据库中.数据模型就像 http://i.stack.imgur.com/CHMPE.png

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 core 时,我所有的计划都失败了.因为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 for my scenerio)

使用自定义AuthorizeAttributeAuthorizationFilter(我读了这个发布 https://stackoverflow.com/a/35863514/5426333 但我无法正确更改)

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

使用自定义中间件(如何获取当前的AuthorizeAttribute行动?)

Using custom middleware(how to get AuthorizeAttribute of current action?)

使用 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 core有什么建议吗?

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 PermissionRequirement(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);
        }
    }
}

并在您的 Startup 类中注册它:

And register it in your Startup class:

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)
{
    ...
}

此解决方案的优点是您还可以为一个需求设置多个处理程序,即如果第一个处理程序成功,则第二个处理程序可以确定它是失败的,您可以将其与 基于资源的授权,无需额外的努力.

The advantage of this solution is that you can also have multiple handlers for a requirement, i.e. if first one succeed the second handler can determine it's a fail and you can use it with resource based authorization with little extra effort.

基于策略的方法是 ASP.NET Core 团队的首选方法.

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

来自blowdart:

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

We don't want you writing custom authorize attributes. If you need to do that we've done something wrong. Instead you should be writing authorization requirements.

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆