2011-04-28 121 views
6

是否每動作限制的可用HTTP動詞是一個好習慣?我的代碼更清潔,沒有[HttpGet],[HttpPost],[HttpPut][HttpDelete]裝飾每個動作,但它也可能不太健壯或安全。我沒有在很多教程或示例代碼中看到這一點,除非動詞是明確要求的,就像有兩個「創建」操作,其中GET版本返回新表單並且POST版本插入新記錄。限制每個動作的HTTP動詞

+0

也許一個更好的方法會是另一種方式,創建自定義屬性,否認你不想要的動詞。從來沒有嘗試過,只是說:-) – goenning 2011-04-28 14:35:09

回答

3

我個人儘量尊重RESTful conventions並指定除了不修改服務器上的任何狀態從而GET操作的HTTP動詞允許用任何HTTP動詞來調用它們。

0

你並不需要指定HTTPGET,其他所有你確實需要

+0

這是否意味着HttpGet在默認情況下,如果沒有指定? – 2011-04-28 14:50:15

+1

這不是「需要」的問題,而是「應該」。如果某個動作用於更新某些內容(例如,來自AJAX POST),則不需要*用[[HttpPost]]標記它,但似乎這將是一個好主意。 – MikeWyatt 2011-04-28 15:39:56

1

是的,我認爲這是一個很好的做法,只能將您的操作限制爲適當的HTTP方法,這樣可以防止惡意請求離開系統,降低可能出現的攻擊的有效性,改善代碼的文檔,執行一個RESTful設計等

是,使用[HttpGet][HttpPost] ..屬性可以使你的代碼難以閱讀,特別是如果你還使用其他屬性一樣[OutputCache][Authorize]

我用一個自定義IActionInvoker的小技巧,而不是使用屬性,我預先給HTTP方法Ë操作方法的名稱,例如:

public class AccountController : Controller { 

    protected override IActionInvoker CreateActionInvoker() { 
     return new HttpMethodPrefixedActionInvoker(); 
    } 

    public ActionResult GetLogOn() { 
     ... 
    } 

    public ActionResult PostLogOn(LogOnModel model, string returnUrl) { 
     ... 
    } 

    public ActionResult GetLogOff() { 
     ... 
    } 

    public ActionResult GetRegister() { 
     ... 
    } 

    public ActionResult PostRegister(RegisterModel model) { 
     ... 
    } 

    [Authorize] 
    public ActionResult GetChangePassword() { 
     ... 
    } 

    [Authorize] 
    public ActionResult PostChangePassword(ChangePasswordModel model) { 
     ... 
    } 

    public ActionResult GetChangePasswordSuccess() { 
     ... 
    } 
} 

注意,這不會改變動作的名稱,這仍然是LogOnLogOffRegister

下面的代碼:

using System; 
using System.Collections.Generic; 
using System.Web.Mvc; 

public class HttpMethodPrefixedActionInvoker : ControllerActionInvoker { 

    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) { 

     var request = controllerContext.HttpContext.Request; 

     string httpMethod = request.GetHttpMethodOverride() 
     ?? request.HttpMethod; 

     // Implicit support for HEAD method. 
     // Decorate action with [HttpGet] if HEAD support is not wanted (e.g. action has side effects) 

     if (String.Equals(httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase)) 
     httpMethod = "GET"; 

     string httpMethodAndActionName = httpMethod + actionName; 

     ActionDescriptor adescr = base.FindAction(controllerContext, controllerDescriptor, httpMethodAndActionName); 

     if (adescr != null) 
     adescr = new ActionDescriptorWrapper(adescr, actionName); 

     return adescr; 
    } 

    class ActionDescriptorWrapper : ActionDescriptor { 

     readonly ActionDescriptor wrapped; 
     readonly string realActionName; 

     public override string ActionName { 
     get { return realActionName; } 
     } 

     public override ControllerDescriptor ControllerDescriptor { 
     get { return wrapped.ControllerDescriptor; } 
     } 

     public override string UniqueId { 
     get { return wrapped.UniqueId; } 
     } 

     public ActionDescriptorWrapper(ActionDescriptor wrapped, string realActionName) { 

     this.wrapped = wrapped; 
     this.realActionName = realActionName; 
     } 

     public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) { 
     return wrapped.Execute(controllerContext, parameters); 
     } 

     public override ParameterDescriptor[] GetParameters() { 
     return wrapped.GetParameters(); 
     } 

     public override object[] GetCustomAttributes(bool inherit) { 
     return wrapped.GetCustomAttributes(inherit); 
     } 

     public override object[] GetCustomAttributes(Type attributeType, bool inherit) { 
     return wrapped.GetCustomAttributes(attributeType, inherit); 
     } 

     public override bool Equals(object obj) { 
     return wrapped.Equals(obj); 
     } 

     public override int GetHashCode() { 
     return wrapped.GetHashCode(); 
     } 

     public override ICollection<ActionSelector> GetSelectors() { 
     return wrapped.GetSelectors(); 
     } 

     public override bool IsDefined(Type attributeType, bool inherit) { 
     return wrapped.IsDefined(attributeType, inherit); 
     } 

     public override string ToString() { 
     return wrapped.ToString(); 
     } 
    } 
}