Krishan Dutt Sharma

Web Developer

Google reCAPTCHA In ASP.NET MVC

Introduction 
 
reCAPTCHA is a free service that protects your website from spam and abuse. This blog shows how to implement reCAPTCHA version 2.0 into an ASP.NET MVC website. 
 
Google reCAPTCHA In ASP.NET MVC 

Step 1 - Get Site & Secret Key for reCAPTCHA from Google

Login to your Google account, then go to the below link.

https://www.google.com/recaptcha/admin#list

Enter your details in the register a new site section. Add a label to identify the site, choose “reCAPTCHA V2" and then add a list of domains.

Also, remember to add localhost if you intend to test it on your local machine,

Google reCAPTCHA In ASP.NET MVC
 
Click Register and you will be provided with your Site & Secret Key,

Google reCAPTCHA In ASP.NET MVC 
 Google reCAPTCHA In ASP.NET MVC
 
First, we add a static class to store our reCAPTCHA “Site Key & Secret Key” to use them later :
  1. public static class SiteSettings  
  2. {  
  3.     public const string GoogleRecaptchaSecretKey = "your secret key here";  
  4.     public const string GoogleRecaptchaSiteKey = "your site key here";  
  5. }  

Step 3 - We should create 2 html helpers

One to generate “reCAPTCHA” in our views that uses the above class values,

  1. public static class GoogleCaptchaHelper  
  2. {  
  3.     public static IHtmlString GoogleCaptcha(this HtmlHelper helper)  
  4.     {  
  5.         const string publicSiteKey = SiteSettings.GoogleRecaptchaSiteKey;  
  6.   
  7.         var mvcHtmlString = new TagBuilder("div")  
  8.         {  
  9.             Attributes =  
  10.             {  
  11.                 new KeyValuePair<string, string>("class""g-recaptcha"),  
  12.                 new KeyValuePair<string, string>("data-sitekey", publicSiteKey)  
  13.             }  
  14.         };  
  15.   
  16.         const string googleCaptchaScript = "<script src='https://www.google.com/recaptcha/api.js'></script>";  
  17.         var renderedCaptcha = mvcHtmlString.ToString(TagRenderMode.Normal);  
  18.   
  19.         return MvcHtmlString.Create($"{googleCaptchaScript}{renderedCaptcha}");  
  20.     }  
  21. }  

A second one to show error message if Captcha is invalid for any reason,

  1. public static class InvalidGoogleCaptchaHelper  
  2. {  
  3.     public static IHtmlString InvalidGoogleCaptchaLabel(this HtmlHelper helper, string errorText)  
  4.     {  
  5.         var invalidCaptchaObj = helper.ViewContext.Controller.TempData["InvalidCaptcha"];  
  6.   
  7.         var invalidCaptcha = invalidCaptchaObj?.ToString();  
  8.         if (string.IsNullOrWhiteSpace(invalidCaptcha)) return MvcHtmlString.Create("");  
  9.   
  10.         var buttonTag = new TagBuilder("span")  
  11.         {  
  12.             Attributes =  
  13.             {  
  14.                 new KeyValuePair<string, string>("class""text text-danger")  
  15.             },  
  16.             InnerHtml = errorText ?? invalidCaptcha  
  17.         };  
  18.   
  19.         return MvcHtmlString.Create(buttonTag.ToString(TagRenderMode.Normal));  
  20.     }  
  21. }  
Step 4
 
Now we need to add a custom attribute to validate submitted Captcha from the form in controller,
  1. public class ValidateGoogleCaptchaAttribute : ActionFilterAttribute  
  2. {  
  3.     public override void OnActionExecuting(ActionExecutingContext filterContext)  
  4.     {  
  5.         const string urlToPost = "https://www.google.com/recaptcha/api/siteverify";  
  6.         const string secretKey = SiteSettings.GoogleRecaptchaSecretKey;  
  7.         var captchaResponse = filterContext.HttpContext.Request.Form["g-recaptcha-response"];  
  8.   
  9.         if (string.IsNullOrWhiteSpace(captchaResponse)) AddErrorAndRedirectToGetAction(filterContext);  
  10.   
  11.         var validateResult = ValidateFromGoogle(urlToPost, secretKey, captchaResponse);  
  12.         if (!validateResult.Success) AddErrorAndRedirectToGetAction(filterContext);  
  13.   
  14.         base.OnActionExecuting(filterContext);  
  15.     }  
  16.   
  17.     private static void AddErrorAndRedirectToGetAction(ActionExecutingContext filterContext)  
  18.     {  
  19.         filterContext.Controller.TempData["InvalidCaptcha"] = "Invalid Captcha !";  
  20.         filterContext.Result = new RedirectToRouteResult(filterContext.RouteData.Values);  
  21.     }  
  22.   
  23.     private static ReCaptchaResponse ValidateFromGoogle(string urlToPost, string secretKey, string captchaResponse)  
  24.     {  
  25.         var postData = "secret=" + secretKey + "&response=" + captchaResponse;  
  26.   
  27.         var request = (HttpWebRequest)WebRequest.Create(urlToPost);  
  28.         request.Method = "POST";  
  29.         request.ContentLength = postData.Length;  
  30.         request.ContentType = "application/x-www-form-urlencoded";  
  31.   
  32.         using (var streamWriter = new StreamWriter(request.GetRequestStream()))  
  33.             streamWriter.Write(postData);  
  34.   
  35.         string result;  
  36.         using (var response = (HttpWebResponse)request.GetResponse())  
  37.         {  
  38.             using (var reader = new StreamReader(response.GetResponseStream()))  
  39.                 result = reader.ReadToEnd();  
  40.         }  
  41.   
  42.         return JsonConvert.DeserializeObject<ReCaptchaResponse>(result);  
  43.     }  
  44. }  
  45.   
  46. internal class ReCaptchaResponse  
  47. {  
  48.     [JsonProperty("success")]  
  49.     public bool Success { get; set; }  
  50.   
  51.     [JsonProperty("challenge_ts")]  
  52.     public string ValidatedDateTime { get; set; }  
  53.   
  54.     [JsonProperty("hostname")]  
  55.     public string HostName { get; set; }  
  56.   
  57.     [JsonProperty("error-codes")]  
  58.     public List<string> ErrorCodes { get; set; }  
  59. }  
Step 5
 
Now to test our applicationwe we are about to create a new controller with 2 actions,
  1. public class TestController : Controller  
  2. {  
  3.     [HttpGet]  
  4.     public ActionResult Create()  
  5.     {  
  6.         return View();  
  7.     }  
  8.   
  9.     [HttpPost]  
  10.     [ValidateAntiForgeryToken]  
  11.     [ValidateGoogleCaptcha]  
  12.     public ActionResult Create(string title)  
  13.     {  
  14.         // If we are here, Captcha is validated.  
  15.         return View();  
  16.     }  
  17. }  
 We validate Captcha in our POST action using [ValidateGoogleCaptcha].

Ours creates a view,

  1. @using GoogleRecaptcha.Infrastructure.HtmlHelpers  
  2.   
  3. @{  
  4.     ViewBag.Title = "Create";  
  5. }  
  6.   
  7. <h2>@ViewBag.Title</h2>  
  8. <h4>Some test form that needs reCAPTCHA !</h4>  
  9.   
  10. <hr />  
  11.   
  12. @using (Html.BeginForm("Create""Test", FormMethod.Post, new { @class = "form-horizontal" }))  
  13. {  
  14.     @Html.AntiForgeryToken()  
  15.   
  16.     <div class="form-group">  
  17.         @Html.Label("Title"new { @class = "control-label col-md-2" })  
  18.         <div class="col-md-10">  
  19.             @Html.TextBox("Title"""new { @class = "form-control" })  
  20.         </div>  
  21.     </div>  
  22.   
  23.     <div class="form-group">  
  24.         <div class="col-md-offset-2 col-md-10">  
  25.             @Html.GoogleCaptcha()  
  26.             @Html.InvalidGoogleCaptchaLabel("Captcha is not valid !")  
  27.         </div>  
  28.     </div>  
  29.   
  30.     <div class="form-group">  
  31.         <div class="col-md-offset-2 col-md-10">  
  32.             <input type="submit" value="Create" class="btn btn-primary" />  
  33.         </div>  
  34.     </div>  
  35. }  

Now that your implementation is done check this OUTPUT

Google reCAPTCHA In ASP.NET MVC
 
Conclusion
 
In this blog, I explain how to implement Google ReCaptcha into our Asp.net MVC application while generating custom Helper Class for the Google ReCaptcha.