MVC Prevent Spam

MVC Prevent Spam

Das folgende Code-Snippet soll als Idee dienen, wie ein doppelter Postback zum Server vermieden werden kann.

Wir erzeugen pro Formular einen eindeutigen Guid, der sich jedes mal ändert, wenn das Formular geöffnet wird.
Dazu habe ich folgenden HTML-Helper geschriben, der die Guid erzeugt und in ein Hidden-Field packt.
public static MvcHtmlString HiddenGuid(this HtmlHelper html, string name)
{
    TagBuilder tag = new TagBuilder("input");
    tag.Attributes.Add("type", "hidden");

    if (string.IsNullOrEmpty(name))
    {
        name = "formid";
    }

    tag.Attributes.Add("name", name);

    string value = html.ViewContext.RequestContext.HttpContext.Request.Form.Get("formid");
    if (string.IsNullOrEmpty(value))
    {
        value = Guid.NewGuid().ToString().Replace("-", "");
    }

    tag.Attributes.Add("value", value);

    return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
}

Danach habe ich ein ActionFilter Attribute geschrieben, welches nun die Guid auswertet.
Der Filter überprüft erstmal, ob die Validierung erfolgreich war. Sollte das der Fall sein, wird die Guid zum Cache hinzugefügt und die Aktion wird weiter ausgeführt.
Wenn nun allerdings erneut ein Post durchgeführt wird, so findet der Filter die Guid bereits im Cache und leitet den Benutzer an die angegebene RedirectURL weiter.
public class PreventSpamAttribute : ActionFilterAttribute
{
    #region Constructor

    public PreventSpamAttribute(string redirectUrl)
        : this(redirectUrl, "formid")
    {
    }

    public PreventSpamAttribute(string redirectUrl, string guidName)
    {
        this.RedirectURL = redirectUrl;
        this.GuidName = guidName;
    }

    #endregion

    #region Methods

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.Controller.ViewData.ModelState.IsValid)
        {
            HttpContextBase http = context.HttpContext;
            HttpRequestBase request = context.HttpContext.Request;

            string guid = request.Form[GuidName];
            if (string.IsNullOrEmpty(guid))
            {
                throw new Exception("Guid not found");
            }

            if (http.Cache[guid] != null)
            {
                context.Result = new RedirectResult(RedirectURL);
            }
            else
            {
                http.Cache.Add(guid, 1,
                    null, DateTime.Now.AddSeconds(120), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);

                base.OnActionExecuting(context);
            }
        }
    }

    #endregion

    #region Properties

    public string RedirectURL { get; set; }
    public string GuidName { get; set; }

    #endregion
}

Ihr könnt euch hier ein Beispiel-Projekt zum herrumprobieren herunterladen.
Bitte bedenkt allerdings, dass es sich hierbei nur um eine Inspiration handelt. Sicher ist diese Variante bei weitem nicht.
Um einen Kommentar zu hinterlassen, ist eine Anmeldung erforderlich.