ASP.Core 3中基于角色的授权:如何在各处授予特定角色访问权限?

时间:2019-12-17 12:16:54

标签: c# asp.net-core .net-core .net-core-3.0 abac

我正在编写一个ABAC系统,在该系统中,我将根据某些角色/属性/等等来决定用户是否可以访问某些数据。但是,有一种特殊的用户(例如超级管理员)可以随时随地访问所有内容。我不想遍历所有策略,控制器,操作和方法并添加对这个特定角色的检查。有没有办法更集中地做到这一点? (例如:在startup中)。

如果无法将其添加到全局位置,则我正在考虑至少在控制器级别上将其全局添加:我在寻找here,并且看到装饰器[Authorize(Roles = "Administrator")]允许您可以仅对管理员用户限制对特定方法/类的访问。但是,我想要一种“相反的”。我的意思是类似AuthorizeAlways的东西,其行为如下:

[AuthorizeAlways(Roles = "SuperAdministrator")]
public class ControlPanelController : Controller
{
    [Authorize(Roles = "SetterUser")]
    public ActionResult SetTime()
    {
    }

    [Authorize(Roles = "PowerUser")]
    [MinimumAgeAuthorize(50)]
    public ActionResult ShutDown()
    {
    }
}

在这种情况下,我希望SuperAdministrator(即使他们49岁)可以访问任何地方。 SetterUser只能访问SetTime,并且只有50岁以上的PowerUser可以访问ShutDown

我不知道这是否有意义。可能吗?我在哪里可以做?谢谢!

1 个答案:

答案 0 :(得分:3)

此博客文章提供了有关如何实现自定义授权的很好的教程: https://seanspaniel.wordpress.com/2019/12/13/custom-authorization-in-asp-net-core-3/

在该教程中,您可以在CustomAuthorizationMiddleware类中检查“ SuperAdministrator”角色并授予对每个端点的访问权限。

public static class CustomAuthorizationMiddleware
{
    public static async Task Authorize(HttpContext httpContext, Func next)
    {
        var endpointMetaData = httpContext.GetEndpoint().Metadata;

        bool hasCustomAuthorizeAttribute = endpointMetaData.Any(x => x is CustomAuthorizeAttribute);

        if (!hasCustomAuthorizeAttribute)
        {
            await next.Invoke();
            return;
        }

        CustomAuthorizeAttribute customAuthorizeAttribute = endpointMetaData
                .FirstOrDefault(x => x is CustomAuthorizeAttribute) as CustomAuthorizeAttribute;

        // Check if user has allowed role or super administrator role
        bool isAuthorized = customAuthorizeAttribute.AllowedUserRoles
            .Any(allowedRole => httpContext.User.IsInRole(allowedRole)) 
             || httpContext.User.IsInRole("SuperAdministrator");

        if (isAuthorized)
        {
            await next.Invoke();
            return;
        }

        httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        await httpContext.Response.WriteAsync("unauthorized");
    }
}