免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Asp.net MVC中防止HttpPost重復(fù)提交

   重復(fù)提交的場(chǎng)景很常見,可能是當(dāng)時(shí)服務(wù)器延遲的原因,如購(gòu)物車物品疊加,重復(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是否有效??聪旅娴拇a:  首先定義一個(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è)

public abstract class PageTokenViewBase : IPageTokenView{    public static readonly string HiddenTokenName = "hiddenToken";    public static readonly string SessionMyToken = "Token";    /// <summary>    /// Generates the page token.    /// </summary>    /// <returns></returns>    public abstract string GeneratePageToken();    /// <summary>    /// Gets the get last page token from Form    /// </summary>    public abstract string GetLastPageToken { get; }    /// <summary>    /// Gets a value indicating whether [tokens match].    /// </summary>    /// <value>    ///   <c>true</c> if [tokens match]; otherwise, <c>false</c>.    /// </value>    public abstract bool TokensMatch { get; }  }


接著是實(shí)現(xiàn)SessionPageTokenView類型,記得需要在驗(yàn)證通過后生成新的Token,對(duì)于這個(gè)Class是把它放到Session中。

    public class SessionPageTokenView : PageTokenViewBase    {        #region PageTokenViewBase        /// <summary>        /// Generates the page token.        /// </summary>        /// <returns></returns>        public override string GeneratePageToken()        {            if (HttpContext.Current.Session[SessionMyToken] != null)            {                return HttpContext.Current.Session[SessionMyToken].ToString();            }            else            {                var token = GenerateHashToken();                HttpContext.Current.Session[SessionMyToken] = token;                return token;            }        }        /// <summary>        /// Gets the get last page token from Form        /// </summary>        public override string GetLastPageToken        {            get            {                return HttpContext.Current.Request.Params[HiddenTokenName];            }        }        /// <summary>        /// Gets a value indicating whether [tokens match].        /// </summary>        /// <value>        ///   <c>true</c> if [tokens match]; otherwise, <c>false</c>.        /// </value>        public override bool TokensMatch        {            get            {                string formToken = GetLastPageToken;                if (formToken != null)                {                    if (formToken.Equals(GeneratePageToken()))                    {                        //Refresh token                        HttpContext.Current.Session[SessionMyToken] = GenerateHashToken();                        return true;                    }                }                return false;            }        }        #endregion         #region Private Help Method        /// <summary>        /// Generates the hash token.        /// </summary>        /// <returns></returns>        private string GenerateHashToken()        {            return Utility.Encrypt(                HttpContext.Current.Session.SessionID + DateTime.Now.Ticks.ToString());        }         #endregion


這里有到一個(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ò)展方法:

public static HtmlString GenerateVerficationToken(this HtmlHelper htmlhelper){    string formValue = Utility.Encrypt(HttpContext.Current.Session.SessionID+DateTime.Now.Ticks.ToString());    HttpContext.Current.Session[PageTokenViewBase.SessionMyToken] = formValue;    string fieldName = PageTokenViewBase.HiddenTokenName;    TagBuilder builder = new TagBuilder("input");    builder.Attributes["type"] = "hidden";    builder.Attributes["name"] = fieldName;    builder.Attributes["value"] = formValue;    return new HtmlString(builder.ToString(TagRenderMode.SelfClosing));}


將輸出這類的HtmlString: 
 

<input name="hiddenToken" type="hidden" value="1AB01826F590A1829E65CBD23CCE8D53" />

我們創(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ā)有幫助。 

(責(zé)任編輯:管理員)
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
asp.net c# request常用
asp.net如何操作Session
Lind.DDD.Authorization用戶授權(quán)介紹
企業(yè)微信機(jī)器人定時(shí)發(fā)送信息
Web API接口設(shè)計(jì)經(jīng)驗(yàn)總結(jié)
Asp.Net WebApi一個(gè)簡(jiǎn)單的Token驗(yàn)證
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服