防止AllowAnonymous

时间:2014-05-31 15:17:49

标签: asp.net-mvc-4

我有一个全局标记为[Authorize]的基本控制器。有没有办法通过简单地添加[AllowAnonymous]属性来阻止继承它的控制器覆盖授权要求?

这是我的确切场景:我有三个基本控制器:一个用于匿名用户,两个用于登录用户,两者都使用[授权]进行全局修饰。创建的每个新控制器都继承自三个基础之一,具体取决于所需的功能。其中一个[授权]控制器包含"高度安全"绝对不应该由匿名用户运行的功能。继承自此"安全"基本控制器使用[AllowAnonymous]意外修饰了一些方法,使匿名用户可以访问" secure"基本控制器中的功能。它在测试中被捕,但我认为防止这种类型的错误是个好主意,我想知道是否有一种简单的方法可以做到这一点。现在,我已经将安全基本控制器中的所有代码都包含在以下块中:

if (Request.IsAuthenticated)
{
    // do stuff
}
else
{
    // redirect to login page, basically simulating what [Authorize] does
}

以上完成了我想要的东西,但它首先打败了全球[授权]装饰的目的。我想象的是:

[Authorize(AllowAnonymousOverride=false)] // this doesn't exist, but might be helpful

有没有更好的方法来实现此功能?

2 个答案:

答案 0 :(得分:2)

执行此操作的正确方法是派生自己的AuthorizeAttribute。默认的AuthorizeAttribute如下所示:

namespace System.Web.Mvc
{
  public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
  {
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
      if (filterContext == null)
      {
        throw new ArgumentNullException("filterContext");
      }

      if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
      {
        throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
      }

      // This is the Important part..
      bool flag = filterContext.ActionDescriptor
                   .IsDefined(typeof(AllowAnonymousAttribute), true)
        || filterContext.ActionDescriptor.ControllerDescriptor
            .IsDefined(typeof(AllowAnonymousAttribute), true);

      if (flag)
      {
        return;
      }

      if (this.AuthorizeCore(filterContext.HttpContext))
      {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        cache.SetProxyMaxAge(new TimeSpan(0L));
        cache.AddValidationCallback(
          new HttpCacheValidateHandler(this.CacheValidateHandler), null);
        return;
      }
      this.HandleUnauthorizedRequest(filterContext);
    }
  }
}

推导自己:

  public class CustomAuthorizeAttribute : AuthorizeAttribute
  {
    public bool IsAllowAnonymousEnabled { get; set; }

    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
      if (filterContext == null)
      {
        throw new ArgumentNullException("filterContext");
      }

      if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
      {
        throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
      }

      // This is the Important part..
      bool flag = IsAllowAnonymousEnabled
        && (filterContext.ActionDescriptor
             .IsDefined(typeof(AllowAnonymousAttribute), true)
        || filterContext.ActionDescriptor.ControllerDescriptor
            .IsDefined(typeof(AllowAnonymousAttribute), true));

      if (flag)
      {
        return;
      }

      if (this.AuthorizeCore(filterContext.HttpContext))
      {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        cache.SetProxyMaxAge(new TimeSpan(0L));
        cache.AddValidationCallback(
          new HttpCacheValidateHandler(this.CacheValidateHandler), null);
        return;
      }
      this.HandleUnauthorizedRequest(filterContext);
    }
  }

用法:

[CustomAuthorizeAttribute(IsAllowAnonymousEnabled = false)]
public class MyController : Controller
{
  [AllowAnonymous]
  public ActionResult Index()
  {
    // This will still execute Authorization regardless of [AllowAnonymous]

    return View();
  }
}

您无法致电base.OnAuthorization(),因为它会允许AllowAnonymous

答案 1 :(得分:0)

首先,您似乎有一个带有某些方法的控制器,然后您的方法是继承它,以便暴露相同的方法。我想知道有两个或更多控制器暴露相同数据的重点是什么。是开发人员的错误,还是你的方法中的自定义例程?

然后,您希望有一个属性可以阻止其他属性,但这在语言和mvc框架中显然是不可能的。

第三,有人编写了一个没有单元测试的控制器,也可能没有测试,但没有人验证这些测试,因此在手动测试阶段就发现了问题。这表明问题更广泛,不仅限于继承 - 假设您的开发人员编写了一个不继承任何东西的控制器,并且由于允许匿名标记,仍然会暴露一些关键数据。那又怎样?即使您对原始问题有补救措施,也无法解决新的问题。

我的建议是将自定义分析器附加到post build事件,该事件扫描所有可能的控制器并列出所有匿名和受限操作,并将其与先前生成的列表进行比较。如果有更改,则会创建一个警报,并且有人必须手动解决问题,方法是批准新创建的操作或拒绝更改,因为已经引入了错误。