【问题标题】:How to include multiple policies如何包含多个策略
【发布时间】:2018-07-20 13:27:39
【问题描述】:

我定义了 2 个策略,ADDSUB,如下所示。

options.AddPolicy("ADD", policy =>
    policy.RequireClaim("Addition", "add"));

options.AddPolicy("SUB", policy =>
    policy.RequireClaim("Substraction", "subs"));

我想做的就是在控制器方法中包含 2 个策略。我该如何执行此操作。

 [Authorize(Policy = "ADD, SUB")]
 [HttpPost]
 public IActionResult PerformCalculation()
 {
 }

但是,这给了我一个错误:

InvalidOperationException:未找到名为“ADD,SUB”的 AuthorizationPolicy

【问题讨论】:

标签: c# asp.net-core


【解决方案1】:

首先要意识到授权属性策略设置是单数的,不像角色可以是复数,并且多个策略是在 AND 基础上处理的,而不是在 OR 基础上处理的角色列表。

在您的示例代码中,“ADD, SUB” 被视为单个策略名称。如果您想将您的方法与这两种策略一起使用,您的代码应如下所示。

[Authorize(Policy = "ADD")]
[Authorize(Policy = "SUB")]
[HttpPost]
public IActionResult PerformCalculation()
{
}

但是,这不会给您任何您想要的效果,或者,由于政策是 AND 在一起的,因此这两个政策必须通过才能获得授权。编写单个策略或要求处理程序来处理多个需求的建议也不会给您在 OR 基础上处理策略的结果。

相反,解决方案是创建一个TypeFilterAttribute,该TypeFilterAttribute 接受策略列表并绑定到一个IAsyncAuthorizationFilter,用于测试或。下面概述了您需要定义的两个类以及如何为您的操作方法设置属性。

以下代码定义了AuthorizeAnyPolicy类的新属性。

/// <summary>
/// Specifies that the class or method that this attribute is applied to requires 
/// authorization based on user passing any one policy in the provided list of policies.
/// </summary>
public class AuthorizeAnyPolicyAttribute : TypeFilterAttribute
{
    /// <summary>
    /// Initializes a new instance of the AuthorizeAnyPolicyAttribute class.
    /// </summary>
    /// <param name="policies">A comma delimited list of policies that are allowed to access the resource.</param>
    public AuthorizeAnyPolicyAttribute(string policies) : base(typeof(AuthorizeAnyPolicyFilter))
    {
        Arguments = new object[] { policies };
    }
}

以下代码定义了授权过滤器类,它循环执行列表中的每个策略。如果所有策略都失败,授权上下文的结果将设置为禁止。

public class AuthorizeAnyPolicyFilter : IAsyncAuthorizationFilter
{
    private readonly IAuthorizationService authorization;
    public string Policies { get; private set; }

    /// <summary>
    /// Initializes a new instance of the AuthorizeAnyPolicyFilter class.
    /// </summary>
    /// <param name="policies">A comma delimited list of policies that are allowed to access the resource.</param>
    /// <param name="authorization">The AuthorizationFilterContext.</param>
    public AuthorizeAnyPolicyFilter(string policies, IAuthorizationService authorization)
    {
        Policies = policies;
        this.authorization = authorization;
    }

    /// <summary>
    /// Called early in the filter pipeline to confirm request is authorized.
    /// </summary>
    /// <param name="context">A context for authorization filters i.e. IAuthorizationFilter and IAsyncAuthorizationFilter implementations.</param>
    /// <returns>Sets the context.Result to ForbidResult() if the user fails all of the policies listed.</returns>
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var policies = Policies.Split(",").ToList();
            
        // Loop through policies.  User need only belong to one policy to be authorized.
        foreach (var policy in policies)
        {
            var authorized = await authorization.AuthorizeAsync(context.HttpContext.User, policy);
            if (authorized.Succeeded)
            {
                return;
            }

        }
            
        context.Result = new ForbidResult();
        return;
    }
}

使用如问题中所示定义的策略,您可以将方法归为如下。

[AuthorizeAnyPolicy("ADD,SUB")]
[HttpPost]
public IActionResult PerformCalculation()
{
}

就这么简单,您会在以下 Stack Overflow 问题中找到类似的解决方案。

【讨论】:

  • 很好的解释。应标记为已接受。 +1 赞成
猜你喜欢
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 2017-03-13
  • 1970-01-01
  • 2020-03-29
  • 1970-01-01
相关资源
最近更新 更多