【问题标题】:Multiple Authorization attributes on method方法上的多个授权属性
【发布时间】:2013-06-20 18:42:40
【问题描述】:

我在为类方法指定两个单独的授权属性时遇到问题:如果两个属性中的任何一个为真,则允许用户访问。

Athorization 类如下所示:

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AuthAttribute : AuthorizeAttribute {
. . .

和行动:

[Auth(Roles = AuthRole.SuperAdministrator)]
[Auth(Roles = AuthRole.Administrator, Module = ModuleID.SomeModule)]
public ActionResult Index() {
    return View(GetIndexViewModel());
}

有没有办法解决这个问题,还是我需要重新考虑我的方法?

这将在 MVC2 中运行。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core


    【解决方案1】:

    在更高版本的 asp.net 中有一种更好的方法来执行此操作,您可以对角色执行 OR 和 AND。这是通过约定完成的,在单个 Authorize 中列出多个角色将执行 OR,而添加多个 Authorize 属性将执行 AND。

    或示例

    [Authorize(Roles = "PowerUser,ControlPanelUser")] 
    

    AND 示例

    [Authorize(Roles = "PowerUser")]
    [Authorize(Roles = "ControlPanelUser")]
    

    您可以在以下链接中找到更多信息 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles

    【讨论】:

    • OR 示例也适用于 .NET Framework(非核心)!
    • 似乎有角色,但没有策略(仅策略)
    【解决方案2】:

    多个AuthorizeAttribute 实例由MVC 处理,就像它们与AND 连接一样。如果您想要 OR 行为,您将需要实现自己的检查逻辑。最好实现AuthAttribute 以承担多个角色并使用OR 逻辑执行自己的检查。

    另一种解决方案是使用标准 AuthorizeAttribute 并实现自定义 IPrincipal,这将实现 bool IsInRole(string role) 方法以提供“或”行为。

    这里有一个例子: https://stackoverflow.com/a/10754108/449906

    【讨论】:

    • 是否可以创建另一个将多个AuthAttributes 作为输入的授权属性(即public class MultipleAuthOrAttribute {)?
    • 您不能创建采用其他属性实例的属性。属性类构造函数只能接受编译时有效值/原始类型。这就是AuthorizeAttribute 将 Roles 作为字符串的原因。
    • 谁能提供支持多个AuthorizeAttribute实例作为逻辑AND处理的声明的官方文档参考。在我自己的测试中,过滤器的顺序似乎很重要,第一个过滤器对身份验证是否成功有最终决定权。
    • 查看我的答案以获取在 asp.net 核心中使用多个 AuthorizationHandlers 的 OR 逻辑。
    【解决方案3】:

    我在生产环境中使用此解决方案已有一段时间了,使用的是 .NET Core 3.0。我想要 自定义属性 和原生 AuthorizeAttribute 之间的 OR 行为。为此,我实现了IAuthorizationEvaluator 接口,在所有授权者评估其结果后立即调用该接口

    /// <summary>
    /// Responsible for evaluating if authorization was successful or not, after execution of
    /// authorization handler pipelines.
    /// This class was implemented because MVC default behavior is to apply an AND behavior
    /// with the result of each authorization handler. But to allow our API to have multiple
    /// authorization handlers, in which the final authorization result is if ANY handlers return
    /// true, the class <cref name="IAuthorizationEvaluator" /> had to be extended to add this
    /// OR behavior.
    /// </summary>
    public class CustomAuthorizationEvaluator : IAuthorizationEvaluator
    {
        /// <summary>
        /// Evaluates the results of all authorization handlers called in the pipeline.
        /// Will fail if: at least ONE authorization handler calls context.Fail() OR none of
        /// authorization handlers call context.Success().
        /// Will succeed if: at least one authorization handler calls context.Success().
        /// </summary>
        /// <param name="context">Shared context among handlers.</param>
        /// <returns>Authorization result.</returns>
        public AuthorizationResult Evaluate(AuthorizationHandlerContext context)
        {
            // If context.Fail() got called in ANY of the authorization handlers:
            if (context.HasFailed == true)
            {
                return AuthorizationResult.Failed(AuthorizationFailure.ExplicitFail());
            }
    
            // If none handler called context.Fail(), some of them could have called
            // context.Success(). MVC treats the context.HasSucceeded with an AND behavior,
            // meaning that if one of the custom authorization handlers have called 
            // context.Success() and others didn't, the property context.HasSucceeded will be
            // false. Thus, this class is responsible for applying the OR behavior instead of
            // the default AND.
    
            bool success = 
                context.PendingRequirements.Count() < context.Requirements.Count();
    
            return success == true 
                ? AuthorizationResult.Success()
                : AuthorizationResult.Failed(AuthorizationFailure.ExplicitFail());
        }
    }
    

    只有在添加到 .NET 服务集合(在您的启动类中)时才会调用此评估器,如下所示:

    services.AddSingleton<IAuthorizationEvaluator, CustomAuthorizationEvaluator>();
    

    在控制器类中,用两个属性装饰每个方法。在我的情况下,[Authorize][CustomAuthorize]

    【讨论】:

      【解决方案4】:

      我不确定其他人对此有何看法,但我也想要 OR 行为。在我的AuthorizationHandlers 中,如果其中任何一个通过了,我就打电话给Succeed。请注意,这不适用于没有参数的内置 Authorize 属性。

      public class LoggedInHandler : AuthorizationHandler<LoggedInAuthReq>
      {
          private readonly IHttpContextAccessor httpContextAccessor;
          public LoggedInHandler(IHttpContextAccessor httpContextAccessor)
          {
              this.httpContextAccessor = httpContextAccessor;
          }
      
          protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, LoggedInAuthReq requirement)
          {
              var httpContext = httpContextAccessor.HttpContext;
              if (httpContext != null && requirement.IsLoggedIn())
              {
                  context.Succeed(requirement);
                  foreach (var req in context.Requirements)
                  {
                      context.Succeed(req);
                  }
              }
      
              return Task.CompletedTask;
          }
      }
      

      提供您自己的 LoggedInAuthReq。在启动时将这些注入到服务中

              services.AddAuthorization(o => {
                  o.AddPolicy("AadLoggedIn", policy => policy.AddRequirements(new LoggedInAuthReq()));
                  ... more here
              });
              services.AddSingleton<IAuthorizationHandler, LoggedInHandler>();
              ... more here
      

      在你的控制器方法中

          [Authorize("FacebookLoggedIn")]
          [Authorize("MsaLoggedIn")]
          [Authorize("AadLoggedIn")]
          [HttpGet("anyuser")]
          public JsonResult AnyUser()
          {
              return new JsonResult(new { I = "did it with Any User!" })
              {
                  StatusCode = (int)HttpStatusCode.OK,
              };
          }
      

      这也可以通过单个属性和一堆if 语句来完成。在这种情况下它是works for me。撰写本文时的 asp.net core 2.2。

      【讨论】:

      猜你喜欢
      • 2019-05-16
      • 2014-08-02
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多