Search code examples
asp.net-mvcspam-preventionrecaptcha

Asking for CAPTCHA only once with MvcReCaptcha


I'm using MvcRecaptcha to prevent bot posts for a complex unauthenticated client form on an ASP.NET MVC 2.0 site.

I only want to require one correct CAPTCHA entry from an unauthenticated client, even if some of the form's inputs are incorrect.

I have tried using a Session["CaptchaSuccess"] = true; variable to suppress Html.GenerateCaptcha() in my view following a successful entry, but the presence of the [CaptchaValidator] attribute on my [HttpPost] view causes an error because it naturally requires some ReCaptcha form inputs.

What is the simplest way to achieve this reliably, including on mobile browsers?


Solution

  • Solved by modifying the [CaptchaValidatorAttribute] OnActionExecuting method, where CaptchaSuccessFieldKey refers to the constant string value "CaptchaSuccess":

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
                bool? bCaptchaSuccess = filterContext.HttpContext.Session[CaptchaSuccessFieldKey] as bool?;
                if (bCaptchaSuccess.HasValue && bCaptchaSuccess.Value)
                {
                    filterContext.ActionParameters["captchaValid"] = true;
                }
                else
                {
    
                    var captchaChallengeValue = filterContext.HttpContext.Request.Form[ChallengeFieldKey];
                    var captchaResponseValue = filterContext.HttpContext.Request.Form[ResponseFieldKey];
                    var captchaValidtor = new Recaptcha.RecaptchaValidator
                                              {
                                                  PrivateKey = ConfigurationManager.AppSettings["ReCaptchaPrivateKey"],
                                                  RemoteIP = filterContext.HttpContext.Request.UserHostAddress,
                                                  Challenge = captchaChallengeValue,
                                                  Response = captchaResponseValue
                                              };
    
                    var recaptchaResponse = captchaValidtor.Validate();
    
                    // this will push the result value into a parameter in our Action
                    filterContext.ActionParameters["captchaValid"] = recaptchaResponse.IsValid;
                }
    
                base.OnActionExecuting(filterContext);
    
                // Add string to Trace for testing
                //filterContext.HttpContext.Trace.Write("Log: OnActionExecuting", String.Format("Calling {0}", filterContext.ActionDescriptor.ActionName));
            }