جلوگیری از ارسال Spam در ASP.NET MVC
نویسنده: علی سالمیان
تاریخ: ۱۳۹۴/۰۹/۱۹ ۱۰:۳۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System;
using System.Linq;
using System.Web.Mvc;
using System.Security.Cryptography;
using System.Text;
using System.Web.Caching;
namespace Parsnet.Core
{
public class StopSpamAttribute : ActionFilterAttribute
{
// حداقل زمان مجاز بین درخواستها برحسب ثانیه
public int DelayRequest = 10;
// پیام خطایی که در صورت رسیدن درخواست غیرمجاز باید صادر کنیم
public string ErrorMessage = "درخواستهای شما در مدت زمان معقولی صورت نگرفته است.";
//خصوصیتی برای تعیین اینکه آدرس درخواست هم به شناسه یکتا افزوده شود یا خیر
public bool AddAddress = true;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// درسترسی به شئی درخواست
var request = filterContext.HttpContext.Request;
// دسترسی به شیئ کش
var cache = filterContext.HttpContext.Cache;
// کاربر IP بدست آوردن
var IP = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress;
// مشخصات مرورگر
var browser = request.UserAgent;
// در اینجا آدرس درخواست جاری را تعیین میکنیم
var targetInfo = (this.AddAddress) ? (request.RawUrl + request.QueryString) : "";
// شناسه یکتای درخواست
var Uniquely = String.Concat(IP, browser, targetInfo);
//در اینجا با کمک هش یک امضا از شناسهی درخواست ایجاد میکنیم
var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(Uniquely)).Select(s => s.ToString("x2")));
// ابتدا چک میکنیم که آیا شناسهی یکتای درخواست در کش موجود نباشد
if (cache[hashValue] != null)
{
// یک خطا اضافه میکنیم ModelState اگر موجود بود یعنی کمتر از زمان موردنظر درخواست مجددی صورت گرفته و به
filterContext.Controller.ViewData.ModelState.AddModelError("ExcessiveRequests", ErrorMessage);
}
else
{
// اگر موجود نبود یعنی درخواست با زمانی بیشتر از مقداری که تعیین کردهایم انجام شده
// پس شناسه درخواست جدید را با پارامتر زمانی که تعیین کرده بودیم به شیئ کش اضافه میکنیم
cache.Add(hashValue, true, null, DateTime.Now.AddSeconds(DelayRequest), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
}
base.OnActionExecuting(filterContext);
}
}
} [HttpPost]
[StopSpam(DelayRequest = 5)]
[ValidateAntiForgeryToken]
public virtual async Task<ActionResult> SendFile(HttpPostedFileBase file, int userid = 0)
{
}
[HttpPost]
[StopSpam(DelayRequest = 30, ErrorMessage = "زمان لازم بین ارسال هر مطلب 30 ثانیه است")]
[ValidateAntiForgeryToken]
public virtual async Task<ActionResult> InsertPost(NewPostModel model)
{
} [HttpPost]
[StopSpam(AddAddress = true, DelayRequest = 20)]
[ValidateAntiForgeryToken]
public Task<ActionResult> InsertPost(NewPostModel model)
{
if (ModelState.IsValid)
{
var newPost = dbContext.InsertPost(model);
if (newPost != null)
{
ViewBag.ExecuteResult = true;
}
}
if (ModelState.IsValidField("ExcessiveRequests") == true)
{
ViewBag.ExecuteResult = false;
}
return View();
} if(!filterContext.Controller.ViewData.ModelState.IsValid)
return;
cache.Add(hashValue, true, null, DateTime.Now.AddSeconds(DelayRequest), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
public string RedirectUrl {get; set; }
...
if(cache[hasValue] != null) {
filterContext.Controller.ViewData.ModelState.AddModelError("...", ...);
filterContext.HttpContext.Response.Redirect(RedirectUrl);
}