在asp.net mvc中使用ActionFilter防止重复提交

防止重复提交的好处:可以预防恶意用户发重复的帖子和垃圾信息出现.


解决方案:
需要创建一个自定义的ActionFilter,重写OnActionExecuting方法
public  class PreventSpamAttribute: ActionFilterAttribute 
{
      public override void OnActionExecuting (ActionExecutingContext filterContext) 
      { base.OnActionExecuting (filterContext); 
      } 
}

定义几个属性     
   一个属性来处理请求之间的延迟。
   有一种机制来唯一识别用户的请求(和他们的目标)。
   一种机制来存储这些信息,因此,它是访问请求发生时。
   ModelState的信息显示错误的输出属性来处理。

让我们开始增加的延迟,这将仅仅是一个整数的值,将表明(以秒为单位)请求一个特定的控制器动作以及一些额外的属性,将存储的信息处理显示的错误和无效的请求重定向之间允许的最小延迟:

public class PreventSpamAttribute : ActionFilterAttribute
{
      //处理请求之间的延迟
      public int DelayRequest = 10;
      //防止多次请求时的错误提示信息
      public string ErrorMessage = "Excessive Request Attempts Detected.";
      //出错时URL重定向
      public string RedirectURL;

      public override void OnActionExecuting(ActionExecutingContext filterContext)
      {
             base.OnActionExecuting(filterContext);
      }
}





确定发出请求的用户和他们的目标

下一步,我们将需要一种方法来存储当前有关用户的信息,并在他们的要求是源于这样我们就可以正确识别。做到这一点的方法之一是将得到一些识别有关用户的信息(如IP地址)“ HTTP_X_FORWARDED_FOR “头(如果不存在,” REMOTE_ADDR “标头值回落)和可能附加用户代理(使用“ USER_AGENT “头),以及进一步磨练我们的用户。

public override void  OnActionExecuting(ActionExecutingContext filterContext)
{
      //存储 HttpContext 
      var request = filterContext.HttpContext.Request;

      //获取IP请求者的IP地址
      var originationInfo = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress;

      //Append the User Agent
      originationInfo += request.UserAgent;

      //目标URL信息
      var targetInfo = request.RawUrl + request.QueryString;

      base.OnActionExecuting(filterContext);
}



生成一个Hash来标识唯一请求

现在,我们有独特的要求为我们的用户和他们的目标信息,我们可以用它来生成哈希将存储和使用,以确定是否垃圾邮件的请求后,可能是有效的。

为此,我们将使用。NET加密库(System.Security.Cryptography)你的字符串值来创建一个简单的MD5哈希值,所以你需要ActionFilter正在申报包括适当的using语句:

using System.Security.Cryptography;

我们可以利用LINQ来执行我们的字符串很短的小单行转换到一个散列字符串,使用这条线:

//Generate a hash for your strings (this appends each of the bytes of the value into a single hashed string
var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo + targetInfo)).Select(s => s.ToString("x2")));

内存储的哈希缓存

我们可以使用散列字符串作为重点,将被保存在缓存中,以确定是否即将请求是重复的,并进行相应的处理。
public override void  OnActionExecuting(ActionExecutingContext filterContext)
{
      //Store our HttpContext 
      var request = filterContext.HttpContext.Request;
      //Store our HttpContext.Cache 
      var cache = filterContext.HttpContext.Cache;

      //Grab the IP Address from the originating Request 
      var originationInfo = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress;

      //Append the User Agent
      originationInfo += request.UserAgent;

      //目标URL信息
      var targetInfo = request.RawUrl + request.QueryString;

      //创建希哈值
      var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo + targetInfo)).Select(s => s.ToString("x2")));

      //如果希哈值在缓存中,(重复提交)
      if (cache[hashValue] != null)
      {
              //添加错误信息
              filterContext.Controller.ViewData.ModelState.AddModelError("ExcessiveRequests", ErrorMessage);
      }
      else
      {
              //使用希哈值的key添加一个空对象到缓存中(决定是否过期)
              //if the Request is valid or not
              cache.Add(hashValue, hashValue, null, DateTime.Now.AddSeconds(DelayRequest), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
      }
      base.OnActionExecuting(filterContext);
}



应用
//Displays your form initially
public ActionResult YourPage()
{
      return View(new TestModel());
}

[HttpPost]
[PreventSpam]
public ActionResult YourPage(TestModel yourModel)
{
      //If your Model was valid - output that it was successful!
      if (ModelState.IsValid)
      {
             return Content("Success!");
      }
      //Otherwise return the model to the View
      else
      {
             return View(yourModel);
      }
}


//This action can only be accessed every 60 seconds and any additional requests within that timespan will 
//notify the user with a custom message. 
[PreventSpam(DelayRequest=60,ErrorMessage="You can only create a new widget every 60 seconds.")]
public ActionResult YourActionName(YourModel model)
{
      //Your Code Here
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值