February 23, 2012
I was looking at the MVC ReCaptcha project available at http://mvcrecaptcha.codeplex.com/. It’s a pretty simple to implement into your MVC project, and its effective for implementing the core captcha capabilities quickly. The framework wraps the ASP.NET web forms control that is available on Google code, for which Google has not created its own MVC implementation (to my knowledge). MVC Recaptcha essentially wraps the ASP.NET version of the control and writes out what the control renders. It also offers an action execution attribute that wraps the Recaptcha validator component. It’s not difficult to implement at all (with full instructions on the web site) and MvcRecaptcha provides the source for you as well. To use it requires adding a captcha control to a MVC or Razor view using:
<%= Html.GenerateCaptcha() %>
When the form posts back, the captcha is validated and the result is pushed to the targeted action method through a captchaValid property. For instance, suppose you had an HttpPost action method, your action can check whether the captcha was valid using:
public ActionResult Save(MyObj obj, bool captchaValid)
ViewBag.Failed = true;
Add the keys that the google recaptcha site gives you to the config file, and you are done. However, I personally did find I needed to make two manipulations to the process. The below code discusses my modifications; please look at the MvcRecaptcha project code to understand the modifications I’m making. First was to the CaptchaValidator attribute. The first modification was to check if the form fields return null, and if they do, return an invalid status immediately.
var captchaChallengeValue = filterContext.HttpContext.Request.Form[ChallengeFieldKey];
var captchaResponseValue = filterContext.HttpContext.Request.Form[ResponseFieldKey];
//Begin Added Code
if (captchaChallengeValue == null || captchaResponseValue == null)
filterContext.ActionParameters[“captchaValid”] = false;
//End Added Code
By default, the validator attribute expects the challenge and response values to be present, supplied by the Recaptcha control. However, there may be scenarios where it is not. For instance, suppose you have a login form (which I have), and you want to only show the captcha after a number of unsuccessful logins. The first X number of attempts won’t show the captcha, but after X number of invalid attempts, the captcha should appear. This modification allows, for the first 3 attempts, to invalidate the response if the keys aren’t even present.
Additionally, the Recaptcha helper renders a string; in switching to Razor in my personal use, an encoded HTML string was the original output. I changed the signature of the helper to:
public static IHtmlString GenerateCaptcha(this HtmlHelper helper)
The control output was the response of a StringWriter.ToString() call; wrapping this with MvcHtmlString as in:
return new MvcHtmlString(htmlWriter.InnerWriter.ToString());
Allows the content to render naturally.