繁体   English   中英

使用 ActionFilterAttribute 向 ASP.NET Core 中的自定义授权策略公开特定于操作的数据

[英]Exposing Action-Specific Data to Custom Authorization Policies in ASP.NET Core using ActionFilterAttribute

我正在使用一种方法(我认为是一种 hack)来传递值以使特定于操作的权限数据可用于自定义授权策略。

问题? 我需要一种将特定于操作的数据传递给授权要求处理程序的方法。

不想在 Startup 中执行此操作

services.AddAuthorization(options =>
        {               
            options.AddPolicy("MyPolicy",policy =>policy.Requirements.Add(new PermissionRequirement(PermissionEnum.CanView)));
        });

这在控制器中

[Authorize(Policy = "MyPolicy")]
public IActionResult MyAction()
    {          
        return View();
    }

因为它需要我有太多的策略,因为我有很多权限。 所以我需要能够在操作级别将PermissionEnum.CanView传递给授权处理程序,以便我可以指定每个操作所需的权限并让相同的处理程序处理它们。

我想不出将值传递给策略属性的方法,所以我这样做了。 我创建了一个自定义ActionFilterAttribute并在那里传递了值

public class AccessAttribute : ActionFilterAttribute
{
    public string Permission { get; }

    public AccessAttribute(PermissionEnum permission)
    {
        Permission =  permission.ToString();
    }
}

然后我像这样使用它

[Access(PermissionEnum.CanView)]
[Authorize(Policy = "MyPolicy")]
public IActionResult MyAction()
{          
    return View();
}

然后在授权处理程序中,我像这样从AuthorizationHandlerContext对象访问这个值

var mvcContext = context.Resource as AuthorizationFilterContext;
var descriptor = mvcContext?.ActionDescriptor as ControllerActionDescriptor;

if (descriptor == null) return Task.CompletedTask;

foreach (var filterMetadata in mvcContext.Filters)
{
if (filterMetadata.GetType().Name != typeof(AccessAttribute).Name) continue;

var PermissionAttribute = filterMetadata as AccessAttribute;

if (PermissionAttribute == null) continue;
if (context.User.HasClaim(c => c.Type == PermissionAttribute.Permission))
{
context.Succeed(requirement);
}
}   

return Task.CompletedTask;

在这里,我以声明的形式授予用户上下文权限,因此我检查用户是否具有指定的操作权限。 最重要的是,我可以通过将权限设置为自定义过滤器中的属性来判断哪些用户可以访问操作。

一切正常,但我想知道这是否可行。 我认为可能有更好的方法来执行此操作,甚至是将值传递给自定义策略的方法。

问题:

1)有没有更好的方法呢?

2)我从调试中注意到我的每个自定义过滤器在开始时运行两次。 这可能不是问题,但我只是想知道为什么twice 它们不会在任何操作被访问时运行(尽管这对我来说很好),因为它是一个硬代码,无论操作执行多少次都不会改变。 我只是想知道这些,但我的第一个问题是我真正关心的问题。

[编辑]基于“传统”ASP.NET MVC 的答案,可以轻松适应 ASP.NET Core MVC。

所以我需要能够在操作级别将 PermissionEnum.CanView 传递给授权处理程序,以便我可以指定每个操作所需的权限并让相同的处理程序处理它们。

一个选项是创建一个自定义 AuthorizeAttribute 以在其构造函数中接收权限:

public class CustomAuthorization : AuthorizeAttribute, IAuthorizationFilter
{
    private readonly string _permission = "";

    // use your Enum instead of string        
    public CustomAuthorization(string permission) : base()
    {
        _permission = permission;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (_permission == "xxx" && Roles.Contains("yyyy"))
        {
            // do something interesting
            return true;
        }
        return false;
    }
}

及其用法:

    [CustomAuthorization("My Permission", Roles = "MyRoles")]
    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";

        return View();
    }

Microsoft 认可的用于完成您想要执行的操作的技术是实现自定义授权策略提供程序。 基本思想是,您将为每个可能的场景(例如MyPolicy_CanView等)使用单独的策略名称,但您不会注册每个; 每次调用具有授权属性的操作方法时,都会调用您的自定义授权策略提供程序,它会看到策略名称与给定模式匹配(例如,在本例中以 MyPolicy_ 开头),然后使用动态创建策略您的一个要求和它从名称中提取的参数(例如本例中的 CanView)。 如果您不希望自定义名称 (MyPolicy_CanView) 出现在您的控制器代码中,您还可以使用自定义属性来构建策略名称。

这是包含详细信息和示例代码的 Microsoft 文档: https : //docs.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-3.1

Hackernoon 描述了该技术,但通过从 DefaultAuthorizationPolicyProvider 派生而不是实现 IAuthorizationPolicyProvider 来实现自定义策略提供程序: https ://hackernoon.com/permission-based-authorization-asp-net-core-with-authorizationpolicyprovider-af4933d575ee

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM