首先要意识到授权属性策略设置是单数的,不像角色可以是复数,并且多个策略是在 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 问题中找到类似的解决方案。