How to implement reCaptcha for ASP.NET MVC?

How to implement reCaptcha in ASP.NET MVC and C #?

+55
c # asp.net-mvc-2
Jan 06 '11 at 2:00
source share
8 answers

There are some great examples:

This has also been discussed earlier in this matter .

NuGet Google reCAPTCHA V2 for MVC 4 and 5

+70
Jan 06 2018-11-11T00:
source share

I added reCaptcha to the project I'm currently working on. I needed to use the AJAX API since the reCaptcha element was loaded dynamically on the page. I could not find any existing controls, and the API is simple, so I created my own.

I will write my code here if anyone finds it useful.

1: add a script tag to the headers of the main page

<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script> 

2: add your keys to web.config

 <appSettings> <add key="ReCaptcha.PrivateKey" value="[key here]" /> <add key="ReCaptcha.PublicKey" value="[key here]" /> </appSettings> 

3: Create Action Attribute and Html Helper Extensions

 namespace [Your chosen namespace].ReCaptcha { public enum Theme { Red, White, BlackGlass, Clean } [Serializable] public class InvalidKeyException : ApplicationException { public InvalidKeyException() { } public InvalidKeyException(string message) : base(message) { } public InvalidKeyException(string message, Exception inner) : base(message, inner) { } } public class ReCaptchaAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var userIP = filterContext.RequestContext.HttpContext.Request.UserHostAddress; var privateKey = ConfigurationManager.AppSettings.GetString("ReCaptcha.PrivateKey", ""); if (string.IsNullOrWhiteSpace(privateKey)) throw new InvalidKeyException("ReCaptcha.PrivateKey missing from appSettings"); var postData = string.Format("&privatekey={0}&remoteip={1}&challenge={2}&response={3}", privateKey, userIP, filterContext.RequestContext.HttpContext.Request.Form["recaptcha_challenge_field"], filterContext.RequestContext.HttpContext.Request.Form["recaptcha_response_field"]); var postDataAsBytes = Encoding.UTF8.GetBytes(postData); // Create web request var request = WebRequest.Create("http://www.google.com/recaptcha/api/verify"); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postDataAsBytes.Length; var dataStream = request.GetRequestStream(); dataStream.Write(postDataAsBytes, 0, postDataAsBytes.Length); dataStream.Close(); // Get the response. var response = request.GetResponse(); using (dataStream = response.GetResponseStream()) { using (var reader = new StreamReader(dataStream)) { var responseFromServer = reader.ReadToEnd(); if (!responseFromServer.StartsWith("true")) ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha words typed incorrectly"); } } } } public static class HtmlHelperExtensions { public static MvcHtmlString GenerateCaptcha(this HtmlHelper helper, Theme theme, string callBack = null) { const string htmlInjectString = @"<div id=""recaptcha_div""></div> <script type=""text/javascript""> Recaptcha.create(""{0}"", ""recaptcha_div"", {{ theme: ""{1}"" {2}}}); </script>"; var publicKey = ConfigurationManager.AppSettings.GetString("ReCaptcha.PublicKey", ""); if (string.IsNullOrWhiteSpace(publicKey)) throw new InvalidKeyException("ReCaptcha.PublicKey missing from appSettings"); if (!string.IsNullOrWhiteSpace(callBack)) callBack = string.Concat(", callback: ", callBack); var html = string.Format(htmlInjectString, publicKey, theme.ToString().ToLower(), callBack); return MvcHtmlString.Create(html); } } } 

4: add captcha to your view

 @using (Html.BeginForm("MyAction", "MyController")) { @Html.TextBox("EmailAddress", Model.EmailAddress) @Html.GenerateCaptcha(Theme.White) <input type="submit" value="Submit" /> } 

5: add attribute to your action

 [HttpPost] [ReCaptcha] public ActionResult MyAction(MyModel model) { if (!ModelState.IsValid) // Will have a Model Error "ReCaptcha" if the user input is incorrect return Json(new { capthcaInvalid = true }); ... other stuff ... } 

6: Note that you will need to reload the captcha after each message, even if it was valid and the other part of the form was invalid. Use Recaptcha.reload();

+27
Oct 18 '11 at 10:12
source share

I have successfully implemented ReCaptcha as follows.
Note: this is in VB, but can be easily converted

1] First, take a copy of the reCaptcha library

2] Then create a custom ReCaptcha HTML helper

  ''# fix SO code coloring issue. <Extension()> Public Function reCaptcha(ByVal htmlHelper As HtmlHelper) As MvcHtmlString Dim captchaControl = New Recaptcha.RecaptchaControl With {.ID = "recaptcha", .Theme = "clean", .PublicKey = "XXXXXX", .PrivateKey = "XXXXXX"} Dim htmlWriter = New HtmlTextWriter(New IO.StringWriter) captchaControl.RenderControl(htmlWriter) Return MvcHtmlString.Create(htmlWriter.InnerWriter.ToString) End Function 

3] Here you will need a server-side validator that can be reused

 Public Class ValidateCaptchaAttribute : Inherits ActionFilterAttribute Private Const CHALLENGE_FIELD_KEY As String = "recaptcha_challenge_field" Private Const RESPONSE_FIELD_KEY As String = "recaptcha_response_field" Public Overrides Sub OnActionExecuting(ByVal filterContext As ActionExecutingContext) If IsNothing(filterContext.HttpContext.Request.Form(CHALLENGE_FIELD_KEY)) Then ''# this will push the result value into a parameter in our Action filterContext.ActionParameters("CaptchaIsValid") = True Return End If Dim captchaChallengeValue = filterContext.HttpContext.Request.Form(CHALLENGE_FIELD_KEY) Dim captchaResponseValue = filterContext.HttpContext.Request.Form(RESPONSE_FIELD_KEY) Dim captchaValidtor = New RecaptchaValidator() With {.PrivateKey = "xxxxx", .RemoteIP = filterContext.HttpContext.Request.UserHostAddress, .Challenge = captchaChallengeValue, .Response = captchaResponseValue} Dim recaptchaResponse = captchaValidtor.Validate() ''# this will push the result value into a parameter in our Action filterContext.ActionParameters("CaptchaIsValid") = recaptchaResponse.IsValid MyBase.OnActionExecuting(filterContext) End Sub 

over this line can be reused ** ONE TIME ** code




below this line shows how easy it is to implement reCaptcha again and again

Now that you have your reusable code ... all you have to do is add captcha to your view.

 <%: Html.reCaptcha %> 

And when you submit the form to your controller ...

  ''# Fix SO code coloring issues <ValidateCaptcha()> <AcceptVerbs(HttpVerbs.Post)> Function Add(ByVal CaptchaIsValid As Boolean, ByVal [event] As Domain.Event) As ActionResult If Not CaptchaIsValid Then ModelState.AddModelError("recaptcha", "*") '#' Validate the ModelState and submit the data. If ModelState.IsValid Then ''# Post the form Else ''# Return View([event]) End If End Function 
+6
Jan 6 2018-11-11T00:
source share

A simple and complete solution works for me. Supports ASP.NET MVC 4 and 5 (supports ASP.NET 4.0, 4.5 and 4.5.1)

Step 1: Install the NuGet package using Install-Package reCAPTCH.MVC "

Step 2: Add your public and private key to your web.config file in the application settings section

 <appSettings> <add key="ReCaptchaPrivateKey" value=" -- PRIVATE_KEY -- " /> <add key="ReCaptchaPublicKey" value=" -- PUBLIC KEY -- " /> </appSettings> 

You can create an API key pair for your site at https://www.google.com/recaptcha/intro/index.html and click "Get reCAPTCHA" at the top of the page.

Step 3: Change the form to enable reCaptcha

 @using reCAPTCHA.MVC @using (Html.BeginForm()) { @Html.Recaptcha() @Html.ValidationMessage("ReCaptcha") <input type="submit" value="Register" /> } 

Step 4 : perform a controller action that will handle the form submission and Captcha validation

 [CaptchaValidator( PrivateKey = "your private reCaptcha Google Key", ErrorMessage = "Invalid input captcha.", RequiredMessage = "The captcha field is required.")] public ActionResult MyAction(myVM model) { if (ModelState.IsValid) //this will take care of captcha { } } 

OR

 public ActionResult MyAction(myVM model, bool captchaValid) { if (captchaValid) //manually check for captchaValid { } } 
+6
Feb 18 '16 at 12:13
source share

Step 1: Integrate the customer site

Paste this snippet before the closing </head> in your HTML template:

 <script src='https://www.google.com/recaptcha/api.js'></script> 

Insert this snippet at the end of the <form> where you want to see the reCAPTCHA widget:

 <div class="g-recaptcha" data-sitekey="your-site-key"></div> 

Step 2: Integrate the site on the server

When your users submit the form into which you integrated reCAPTCHA, you will receive, as part of the payload, a string named "g-recaptcha-response". To check whether Google has verified this user, send a POST request with these parameters:

URL: https://www.google.com/recaptcha/api/siteverify

secret: your secret key

response: The value of "g-recaptcha-response".

Now in action of your MVC application:

 // return ActionResult if you want public string RecaptchaWork() { // Get recaptcha value var r = Request.Params["g-recaptcha-response"]; // ... validate null or empty value if you want // then // make a request to recaptcha api using (var wc = new WebClient()) { var validateString = string.Format( "https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", "your_secret_key", // secret recaptcha key r); // recaptcha value // Get result of recaptcha var recaptcha_result = wc.DownloadString(validateString); // Just check if request make by user or bot if (recaptcha_result.ToLower().Contains("false")) { return "recaptcha false"; } } // Do your work if request send from human :) } 
+3
Dec 01 '15 at 10:21
source share

For someone else watching, here is a decent set of steps. http://forums.asp.net/t/1678976.aspx/1

Remember to manually add your key to OnActionExecuting (), like me.

+1
Oct 27 2018-11-22T00:
source share

Extending Magpie's answer, here is the code for the action filter that I use in my project.

It works with ASP Core RC2!

 public class ReCaptchaAttribute : ActionFilterAttribute { private readonly string CAPTCHA_URL = "https://www.google.com/recaptcha/api/siteverify"; private readonly string SECRET = "your_secret"; public override void OnActionExecuting(ActionExecutingContext filterContext) { try { // Get recaptcha value var captchaResponse = filterContext.HttpContext.Request.Form["g-recaptcha-response"]; using (var client = new HttpClient()) { var values = new Dictionary<string, string> { { "secret", SECRET }, { "response", captchaResponse }, { "remoteip", filterContext.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString() } }; var content = new FormUrlEncodedContent(values); var result = client.PostAsync(CAPTCHA_URL, content).Result; if (result.IsSuccessStatusCode) { string responseString = result.Content.ReadAsStringAsync().Result; var captchaResult = JsonConvert.DeserializeObject<CaptchaResponseViewModel>(responseString); if (!captchaResult.Success) { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha not solved"); } } else { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha error"); } } } catch (System.Exception) { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Unknown error"); } } } 

And use it in your code like

 [ReCaptcha] public IActionResult Authenticate() { if (!ModelState.IsValid) { return View( "Login", new ReturnUrlViewModel { ReturnUrl = Request.Query["returnurl"], IsError = true, Error = "Wrong reCAPTCHA" } ); } 
+1
Jun 13 '16 at 11:35
source share

Asynchronous version for MVC 5 (i.e. avoiding ActionFilterAttribute, which is not asynchronous until MVC 6) and reCAPTCHA 2

ExampleController.cs

 public class HomeController : Controller { [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> ContactSubmit( [Bind(Include = "FromName, FromEmail, FromPhone, Message, ContactId")] ContactViewModel model) { if (!await RecaptchaServices.Validate(Request)) { ModelState.AddModelError(string.Empty, "You have not confirmed that you are not a robot"); } if (ModelState.IsValid) { ... 

ExampleView.cshtml

 @model MyMvcApp.Models.ContactViewModel @*This is assuming the master layout places the styles section within the head tags*@ @section Styles { @Styles.Render("~/Content/ContactPage.css") <script src='https://www.google.com/recaptcha/api.js'></script> } @using (Html.BeginForm("ContactSubmit", "Home",FormMethod.Post, new { id = "contact-form" })) { @Html.AntiForgeryToken() ... <div class="form-group"> @Html.LabelFor(m => m.Message) @Html.TextAreaFor(m => m.Message, new { @class = "form-control", @cols = "40", @rows = "3" }) @Html.ValidationMessageFor(m => m.Message) </div> <div class="row"> <div class="g-recaptcha" data-sitekey='@System.Configuration.ConfigurationManager.AppSettings["RecaptchaClientKey"]'></div> </div> <div class="row"> <input type="submit" id="submit-button" class="btn btn-default" value="Send Your Message" /> </div> } 

RecaptchaServices.cs

 using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Web; using System.Configuration; using System.Net.Http; using System.Net.Http.Headers; using Newtonsoft.Json; using System.Runtime.Serialization; namespace MyMvcApp.Services { public class RecaptchaServices { //ActionFilterAttribute has no async for MVC 5 therefore not using as an actionfilter attribute - needs revisiting in MVC 6 internal static async Task<bool> Validate(HttpRequestBase request) { string recaptchaResponse = request.Form["g-recaptcha-response"]; if (string.IsNullOrEmpty(recaptchaResponse)) { return false; } using (var client = new HttpClient { BaseAddress = new Uri("https://www.google.com") }) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("secret", ConfigurationManager.AppSettings["RecaptchaSecret"]), new KeyValuePair<string, string>("response", recaptchaResponse), new KeyValuePair<string, string>("remoteip", request.UserHostAddress) }); var result = await client.PostAsync("/recaptcha/api/siteverify", content); result.EnsureSuccessStatusCode(); string jsonString = await result.Content.ReadAsStringAsync(); var response = JsonConvert.DeserializeObject<RecaptchaResponse>(jsonString); return response.Success; } } [DataContract] internal class RecaptchaResponse { [DataMember(Name = "success")] public bool Success { get; set; } [DataMember(Name = "challenge_ts")] public DateTime ChallengeTimeStamp { get; set; } [DataMember(Name = "hostname")] public string Hostname { get; set; } [DataMember(Name = "error-codes")] public IEnumerable<string> ErrorCodes { get; set; } } } } 

web.config

 <configuration> <appSettings> <!--recaptcha--> <add key="RecaptchaSecret" value="***secret key from https://developers.google.com/recaptcha***" /> <add key="RecaptchaClientKey" value="***client key from https://developers.google.com/recaptcha***" /> </appSettings> </configuration> 
+1
Jan 13 '17 at 9:28
source share



All Articles