2009-12-21 23 views

回答

22

是的。你可以通过创建你自己的BaseController来继承Mvc控制器,并重载OnAuthorization()。你要强制执行之前,以确保它是一个POST事件:

public abstract class MyBaseController : Controller 
{ 
    protected override void OnAuthorization(AuthorizationContext filterContext) 
    { 
    //enforce anti-forgery stuff for HttpVerbs.Post 
    if (String.Compare(filterContext.HttpContext.Request.HttpMethod, 
      System.Net.WebRequestMethods.Http.Post, true) == 0) 
    { 
     var forgery = new ValidateAntiForgeryTokenAttribute(); 
     forgery.OnAuthorization(filterContext); 
    } 
    base.OnAuthorization(filterContext); 
    } 
} 

一旦你的,确保所有控制器,从这个MyBaseController(或者无论你怎么称呼它)继承。或者,如果您喜欢使用相同的代码,则可以在每个控制器上执行此操作。

+1

此解决方案接缝不适用于MVC2。它对MVC1来说工作得很好,但是一旦我们升级到v2,它就停止工作。试图找到一个解决方案。 – 2010-03-29 12:14:03

+0

感谢您将此引入我的注意。我也会考虑一下。 – eduncan911 2010-03-29 14:00:37

+1

我至少发现_a_解决方案,而不是最好的解决方案。请参阅下面的答案。评论框不是很好,代码格式=) – 2010-03-29 14:55:15

8

听起来像你试图阻止“哎呀我忘了设置”的错误。如果是这样,我认为最好的地方是使用自定义的ControllerActionInvoker。

基本上你想要做的是,即使找到一个动作没有防伪标记停止MVC:

public class MustHaveAntiForgeryActionInvoker : ControllerActionInvoker 
{ 
    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) 
    { 
     var foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName); 

     if(foundAction.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), true).Length == 0) 
      throw new InvalidOperationException("Can't find a secure action method to execute"); 

     return foundAction; 
    } 
} 

然后在你的控制器,最好是你的基本控制器:

ActionInvoker = new MustHaveAntiForgeryActionInvoker(); 

只是想添加自定义控制器基类往往会变得“厚”,而且它始终是最好的实践,以便使用MVC的卓越可扩展性来抓住它们所属的特性。

这里是大多数的MVC的扩展点有很好的指导: http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx

7

好吧,我刚刚升级了一个项目,MVC V2.0这里,和eduncan911的解决方案不工作了,如果你使用的AuthorizeAttribute你的控制器动作。找出原因有点难。

因此,故事中的罪魁祸首是MVC团队在RequestVerificationToken的值中添加了使用ViewContext.HttpContext.User.Identity.Name属性。

在基本控制器中重写的OnAuthorization在控制器动作的任何过滤器之前执行。所以,问题在于Authorize属性尚未被调用,因此未设置ViewContext.HttpContext.User。所以UserName是String.Empty,而用于验证的AntiForgeryToken包含真正的用户名= fail。

我们使用此代码现在解决了这个问题:

public abstract class MyBaseController : Controller 
{ 
    protected override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     //enforce anti-forgery stuff for HttpVerbs.Post 
     if (String.Compare(filterContext.HttpContext.Request.HttpMethod, "post", true) == 0) 
     { 
      var authorize = new AuthorizeAttribute(); 
      authorize.OnAuthorization(filterContext); 
      if (filterContext.Result != null) // Short circuit validation 
       return; 
      var forgery = new ValidateAntiForgeryTokenAttribute(); 
      forgery.OnAuthorization(filterContext); 
     } 
     base.OnAuthorization(filterContext); 
    } 
} 

到MVC代码库的一些参考文献:

ControllerActionInvoker#InvokeAuthorizationFilters()线283相同短路。 AntiForgeryData#GetUsername()第98行。新功能。

+0

我继续前进,并给雅上升(+3,哇!)。但是,我在3.5框架中使用了VS2010 RTM的MVC 2.0 RTM(这是一个Azure项目,所以我现在必须保持3.5)。我发布的防伪解决方案仍然有效。我想知道这个问题是你使用MVC 2.0 RC2还是一样? – eduncan911 2010-04-26 01:08:22

0

这个怎么样?

[ValidateAntiForgeryToken] 
public class MyBaseController : Controller 
{ 
} 
相关问题