Asp.net MVC中防止HttpPost重复提交
重復提交的場景很常見,可能是當時服務器延遲的原因,如購物車物品疊加,重復提交多個訂單。常見的解決方法是提交后把Button在客戶端Js禁用,或是用Js禁止后退鍵等。在ASP.NET MVC 3?Web Application中 如何去防止這類HTTP-Post的重復提交呢? 我們可以借助Session,放置一個Token在View/Page上,然后在Server端去驗證是不是同一個Token來判斷此次Http-Post是否有效。看下面的代碼:? 首先定義一個接口,便于擴展。
public interface IPageTokenView {/// <summary>/// Generates the page token./// </summary>string GeneratePageToken();/// <summary>/// Gets the get last page token from Form/// </summary>string GetLastPageToken { get; }/// <summary>/// Gets a value indicating whether [tokens match]./// </summary>/// <value>/// <c>true</c> if [tokens match]; otherwise, <c>false</c>./// </value>bool TokensMatch { get; } }
定義一個Abstract Class,包含一個
接著是實現SessionPageTokenView類型,記得需要在驗證通過后生成新的Token,對于這個Class是把它放到Session中。
這里有到一個簡單的加密方法,你可以實現自己的加密方法.?
public static string Encrypt(string plaintext) {string cl1 = plaintext;string pwd = string.Empty;MD5 md5 = MD5.Create();byte[] s = md5.ComputeHash(Encoding.Unicode.GetBytes(cl1));for (int i = 0; i < s.Length; i++){pwd = pwd + s[i].ToString("X");}return pwd; }我們再來編寫一個Attribute繼承FilterAttribute, 實現IAuthorizationFilter接口。然后比較Form中Token與Session中是否一致,不一致就Throw Exception. Tips:這里最好使用依賴注入IPageTokenView類型,增加Logging 等機制?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class ValidateReHttpPostTokenAttribute : FilterAttribute, IAuthorizationFilter {public IPageTokenView PageTokenView { get; set; }/// <summary>/// Initializes a new instance of the <see cref="ValidateReHttpPostTokenAttribute"/> class./// </summary>public ValidateReHttpPostTokenAttribute(){//It would be better use DI inject it.PageTokenView = new SessionPageTokenView();}/// <summary>/// Called when authorization is required./// </summary>/// <param name="filterContext">The filter context.</param>public void OnAuthorization(AuthorizationContext filterContext){if (filterContext == null){throw new ArgumentNullException("filterContext");}if (!PageTokenView.TokensMatch){//log...throw new Exception("Invaild Http Post!");}} }
還需要一個HtmlHelper的擴展方法:
將輸出這類的HtmlString:?
我們創建一個叫_ViewToken.cshtml的Partial View,這樣便于模塊化,讓我們輕易加入到具體View里,就兩行代碼,第一行是擴展方法NameSpace
@using Mvc3App.Models; @Html.GenerateVerficationToken()假設我們這里有一個簡單的Login.cshtml,然后插入其中:
<form method="post" id="form1" action="@Url.Action("Index")"><p>@Html.Partial("_ViewToken")UserName:<input type="text" id="fusername" name="fusername" /><br />Password:<input type="password" id="fpassword" name="fpassword" /><input type="submit" value="Sign-in" /></p></form>
這里我們Post的Index Action,看Controller代碼,我們在Index上加上ValidateReHttpPostToken的attribute.
[HttpPost] [ValidateReHttpPostToken] public ActionResult Index(FormCollection formCollection) {return View(); }public ActionResult Login() {return View(); }
好的,完了,由于篇幅有限,單元測試代碼不貼了。讓我們運行程序在IE中. 正常點擊Button后提交表單,此時按F5再次提交,看到這個提示框:
點擊Retry后,這時就會出現預期Exception,這里只是為了演示,實際中可能需要記錄日志,做異常處理。
Invaild Http Post!
Description:?An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.?Exception Details:?System.Exception: Invaild Http Post!?
有興趣您可以自己試一下,希望對您Web開發有幫助。
總結
以上是生活随笔為你收集整理的Asp.net MVC中防止HttpPost重复提交的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用户 'sa' 登录失败。 (Micro
- 下一篇: 美股t+0还是t+1