Sammy Ageil

Lead by example

User friendly captcha in MVC

June 18
by Sammy Ageil 18. June 2012 08:32

 While we all agree on the need to have CAPTCHA validation components, most of us hate them. 

Most ASP.NET applications use Recaptcha which work quiet well, sometimes it’s too good, even a human being cannot read it.
Others it just spits out some no so user friendly words for the users to validate.

Have a look

Imagine how a user would feel if asked to type in one of the words listed on CAPCHA’s shown on the previous link. Some would say, no big deal, users can regenerate the CAPTCHA if they can’t read or don’t like the challenge words/characters. For those I would highly recommend a web usability book called “Don’t make me think”.

For an ASP.NET web form solution, please see Phil Haak’s honeybotcaptcha control.

To apply the same idea using MVC, I came up with this solution.

The solution utilizes MVC’s ActionFilterAtteribute to perform the validation.

Enough talking and let’s see the code.

First, here is our big helper method.
 

 

public static HtmlString Captcha(this HtmlHelper htmlHelper)

        {

            string captchainput = string.Format("<input type=\"{0}\" name=\"{1}\" value=\"{2}\" style=\"{3}\"  />", "text", "Captcha", string.Empty, "display :none;  speak: none;");

            return new HtmlString(captchainput);

        }

Two things to notice from this code, 

  1. Our input always has an empty value
               
    • Display is set to none to hide it from humans “spam bots ignore css”
    • Speak is set to none to avoid confusing screen readers
  2. The inline style sets both display and speak to none.

Second, our Filter 

public class ValidateCaptcha : ActionFilterAttribute

    {

        public override void OnActionExecuting(ActionExecutingContext filterContext)

        {

            base.OnActionExecuting(filterContext);

              var captcha = filterContext.HttpContext.Request.Form["Captcha"];

      if(!string.IsNullOrEmpty(captcha))

          

            ((Controller)filterContext.Controller).ModelState.AddModelError("", "SPAM SUCKS");



        }

      
    }

Since the solution utilizes an AtionFilter, this code will only run when a control action is marked with 

[ValidateCaptcha]

Third, our view we would use our helper like this.

@using (Html.BeginForm("create","index", FormMethod.Post,null)) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Comment</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Subject)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Subject)
            @Html.ValidationMessageFor(model => model.Subject)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Message)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Message)
            @Html.ValidationMessageFor(model => model.Message)
        </div>
        @Html.Captcha()
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

     

And finally our ActionResult 

[ValidateCaptcha]

        [HttpPost]

        public ActionResult Create(Comment model )

        {

            if(TryUpdateModel(model))

            {

                return View(model);

            

            }

            return View("index");

        }

 

 A spam bot will end up seeing this page when the form is submitted.

Tags: ,

Asp.Net | C# | Captcha | MVC

Comments (1) -

6/22/2012 2:42:36 PM #

Jim Benstrad

Excellent job!
Thanks for sharing

Jim

Jim Benstrad Canada

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading