2009-12-21 22 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 
{ 
} 
相關問題