Asp.net MVC中防止HttpPost重复提交
重復(fù)提交的場(chǎng)景很常見,可能是當(dāng)時(shí)服務(wù)器延遲的原因,如購物車物品疊加,重復(fù)提交多個(gè)訂單。常見的解決方法是提交后把Button在客戶端Js禁用,或是用Js禁止后退鍵等。在ASP.NET MVC 3?Web Application中 如何去防止這類HTTP-Post的重復(fù)提交呢? 我們可以借助Session,放置一個(gè)Token在View/Page上,然后在Server端去驗(yàn)證是不是同一個(gè)Token來判斷此次Http-Post是否有效。看下面的代碼:? 首先定義一個(gè)接口,便于擴(kuò)展。
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; } }
定義一個(gè)Abstract Class,包含一個(gè)
接著是實(shí)現(xiàn)SessionPageTokenView類型,記得需要在驗(yàn)證通過后生成新的Token,對(duì)于這個(gè)Class是把它放到Session中。
這里有到一個(gè)簡(jiǎn)單的加密方法,你可以實(shí)現(xiàn)自己的加密方法.?
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; }我們?cè)賮砭帉懸粋€(gè)Attribute繼承FilterAttribute, 實(shí)現(xiàn)IAuthorizationFilter接口。然后比較Form中Token與Session中是否一致,不一致就Throw Exception. Tips:這里最好使用依賴注入IPageTokenView類型,增加Logging 等機(jī)制?
[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!");}} }
還需要一個(gè)HtmlHelper的擴(kuò)展方法:
將輸出這類的HtmlString:?
我們創(chuàng)建一個(gè)叫_ViewToken.cshtml的Partial View,這樣便于模塊化,讓我們輕易加入到具體View里,就兩行代碼,第一行是擴(kuò)展方法NameSpace
@using Mvc3App.Models; @Html.GenerateVerficationToken()假設(shè)我們這里有一個(gè)簡(jiǎn)單的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代碼,我們?cè)贗ndex上加上ValidateReHttpPostToken的attribute.
[HttpPost] [ValidateReHttpPostToken] public ActionResult Index(FormCollection formCollection) {return View(); }public ActionResult Login() {return View(); }
好的,完了,由于篇幅有限,單元測(cè)試代碼不貼了。讓我們運(yùn)行程序在IE中. 正常點(diǎn)擊Button后提交表單,此時(shí)按F5再次提交,看到這個(gè)提示框:
點(diǎn)擊Retry后,這時(shí)就會(huì)出現(xiàn)預(yù)期Exception,這里只是為了演示,實(shí)際中可能需要記錄日志,做異常處理。
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!?
有興趣您可以自己試一下,希望對(duì)您Web開發(fā)有幫助。
總結(jié)
以上是生活随笔為你收集整理的Asp.net MVC中防止HttpPost重复提交的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用户 'sa' 登录失败。 (Micro
- 下一篇: MVC中提示错误:从客户端中检测到有潜在