ImpIntroduction
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.
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,
Click Register and you will be provided with your
Site & Secret Key,
- Site key - is used to display the widget in your page or code.
- Secret key - can be used as communication between your site and Google to verify the user response whether the reCAPTCHA is valid or not.
Now the next step displays the reCAPTCHA widget on your website.
Step 2 - Using reCAPTCHA in our ASP.NET MVC Application
Now we create a new ASP.NET MVC empty project,
First, we add a static class to store our reCAPTCHA “Site Key & Secret Key” to use them later :
- public static class SiteSettings
- {
- public const string GoogleRecaptchaSecretKey = "your secret key here";
- public const string GoogleRecaptchaSiteKey = "your site key here";
- }
Step 3 - We should create 2 html helpers
One to generate “reCAPTCHA” in our views that uses the above class values,
- public static class GoogleCaptchaHelper
- {
- public static IHtmlString GoogleCaptcha(this HtmlHelper helper)
- {
- const string publicSiteKey = SiteSettings.GoogleRecaptchaSiteKey;
-
- var mvcHtmlString = new TagBuilder("div")
- {
- Attributes =
- {
- new KeyValuePair<string, string>("class", "g-recaptcha"),
- new KeyValuePair<string, string>("data-sitekey", publicSiteKey)
- }
- };
-
- const string googleCaptchaScript = "<script src='https://www.google.com/recaptcha/api.js'></script>";
- var renderedCaptcha = mvcHtmlString.ToString(TagRenderMode.Normal);
-
- return MvcHtmlString.Create($"{googleCaptchaScript}{renderedCaptcha}");
- }
- }
A second one to show error message if Captcha is invalid for any reason,
- public static class InvalidGoogleCaptchaHelper
- {
- public static IHtmlString InvalidGoogleCaptchaLabel(this HtmlHelper helper, string errorText)
- {
- var invalidCaptchaObj = helper.ViewContext.Controller.TempData["InvalidCaptcha"];
-
- var invalidCaptcha = invalidCaptchaObj?.ToString();
- if (string.IsNullOrWhiteSpace(invalidCaptcha)) return MvcHtmlString.Create("");
-
- var buttonTag = new TagBuilder("span")
- {
- Attributes =
- {
- new KeyValuePair<string, string>("class", "text text-danger")
- },
- InnerHtml = errorText ?? invalidCaptcha
- };
-
- return MvcHtmlString.Create(buttonTag.ToString(TagRenderMode.Normal));
- }
- }
Step 4
Now, we need to add a custom attribute to validate submitted Captcha from the form in the controller.
- public class ValidateGoogleCaptchaAttribute : ActionFilterAttribute
- {
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- const string urlToPost = "https://www.google.com/recaptcha/api/siteverify";
- const string secretKey = SiteSettings.GoogleRecaptchaSecretKey;
- var captchaResponse = filterContext.HttpContext.Request.Form["g-recaptcha-response"];
-
- if (string.IsNullOrWhiteSpace(captchaResponse)) AddErrorAndRedirectToGetAction(filterContext);
-
- var validateResult = ValidateFromGoogle(urlToPost, secretKey, captchaResponse);
- if (!validateResult.Success) AddErrorAndRedirectToGetAction(filterContext);
-
- base.OnActionExecuting(filterContext);
- }
-
- private static void AddErrorAndRedirectToGetAction(ActionExecutingContext filterContext)
- {
- filterContext.Controller.TempData["InvalidCaptcha"] = "Invalid Captcha !";
- filterContext.Result = new RedirectToRouteResult(filterContext.RouteData.Values);
- }
-
- private static ReCaptchaResponse ValidateFromGoogle(string urlToPost, string secretKey, string captchaResponse)
- {
- var postData = "secret=" + secretKey + "&response=" + captchaResponse;
-
- var request = (HttpWebRequest)WebRequest.Create(urlToPost);
- request.Method = "POST";
- request.ContentLength = postData.Length;
- request.ContentType = "application/x-www-form-urlencoded";
-
- using (var streamWriter = new StreamWriter(request.GetRequestStream()))
- streamWriter.Write(postData);
-
- string result;
- using (var response = (HttpWebResponse)request.GetResponse())
- {
- using (var reader = new StreamReader(response.GetResponseStream()))
- result = reader.ReadToEnd();
- }
-
- return JsonConvert.DeserializeObject<ReCaptchaResponse>(result);
- }
- }
-
- internal class ReCaptchaResponse
- {
- [JsonProperty("success")]
- public bool Success { get; set; }
-
- [JsonProperty("challenge_ts")]
- public string ValidatedDateTime { get; set; }
-
- [JsonProperty("hostname")]
- public string HostName { get; set; }
-
- [JsonProperty("error-codes")]
- public List<string> ErrorCodes { get; set; }
- }
Step 5
Now, to test our application, we are about to create a new controller with 2 actions.
- public class TestController : Controller
- {
- [HttpGet]
- public ActionResult Create()
- {
- return View();
- }
-
- [HttpPost]
- [ValidateAntiForgeryToken]
- [ValidateGoogleCaptcha]
- public ActionResult Create(string title)
- {
-
- return View();
- }
- }
We validate Captcha in our POST action using [ValidateGoogleCaptcha].
Ours creates a view,
- @using GoogleRecaptcha.Infrastructure.HtmlHelpers
-
- @{
- ViewBag.Title = "Create";
- }
-
- <h2>@ViewBag.Title</h2>
- <h4>Some test form that needs reCAPTCHA !</h4>
-
- <hr />
-
- @using (Html.BeginForm("Create", "Test", FormMethod.Post, new { @class = "form-horizontal" }))
- {
- @Html.AntiForgeryToken()
-
- <div class="form-group">
- @Html.Label("Title", new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBox("Title", "", new { @class = "form-control" })
- </div>
- </div>
-
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- @Html.GoogleCaptcha()
- @Html.InvalidGoogleCaptchaLabel("Captcha is not valid !")
- </div>
- </div>
-
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- <input type="submit" value="Create" class="btn btn-primary" />
- </div>
- </div>
- }
Now that your implementation is done,, check this OUTPUT.
Conclusion
In this blog, I explained how to implement Google ReCaptcha into our ASP.NET MVC application while generating custom Helper Class for the Google ReCaptcha.