Integrate reCaptcha V2 in ASP.NET Applications (Web Forms / MVC / Core)
If you are running any website that makes use of
Google's
reCAPTCHA for keeping bots and automated scripts away, you are probably
aware that version 1.0 is being phased out. That means you need to integrate
version 2.0 into your websites. To that end this article explains how to do just
that. I use ASP.NET MVC project to illustrate the integration process but the
same applies even for ASP.NET Web Forms and ASP.NET Core applications.
The reCaptcha V2 basically shows the end user a checkbox. They need to check
the checkbox in order to prove that a bot is not at work. Depending on some
internal logic they may also be presented with additional verification checks
(for example, check all cars from a set of images). This all happens on the
client side. However, upon submitting the form you need to evaluate whether the
reCaptcha has been successfully solved by the end user. Only if the reCaptcha
has been solved you will like to invoke the intended operation (say, a database
INSERT). Thus, the overall verification process can be summarized like this :
- End user requests a page that has reCaptcha embedded on it
- The reCaptcha is rendered on the page and is shown to the user
- End user attempts tp solve the captcha
- The form is posted back to the server
- Server side code evaluates the result of reCaptcha verification process.
- Depending on the outcome of the previous step you perform some operation
or throw / show error to the user.
We will implement this whole process in the following easy steps.
Step 1 - Get an API key pair
Before you begin any development integrate reCaptcha in your application you
need to generate a reCaptcha key pair. The key pair consists of two keys - Site
Key and Secret Key. The former key is embedded in your HTML markup and is a
public key. The latter key is a private key and is used by your server side
code. You must keep this key secret (and hence the name).
To get this key pair go
here and click on
the Get reCAPTCHA button on the right hand side top. Then fill the key
registration form and click on the Register button to generate the keys. The
registration form captures details such as a list of domains where these keys
will be used and a friendly name for the key pair. Once you generate the keys
keep them ready with you so that you can use them in the following steps.
Step 2 - Create an ASP.NET MVC project
Now, create an ASP.NET project - Web Forms, ASP.NET MVC, or ASP.NET Core.
Most of the steps discussed below remain the same irrespective of the flavor of
ASP.NET you use. As an example I am going to use ASP.NET MVC project. So, go
ahead and create your project.
Once the project is created, create a ReCaptchaV2 folder under the project
root. This is where we will store our reCaptcha class files. For ASP.NET MVC and
ASP.NET Core projects add a HomeController and Index view as you normally do in
your applications. For Web Forms project add Default.aspx under the root.
Step 3 - Add a script reference to reCaptcha library
Open the Index view and add the following script reference in the head
section. For Web Forms project open Default.aspx and do the same.
<script src='https://www.google.com/recaptcha/api.js'></script>
This was your web page gets the reCaptcha library for further use.
Step 4 - Mark the region where reCaptcha will be rendered
Depending on the layout of the page and the nature of the data entry form,
you will need to decide where exactly you would like to display the reCaptcha to
the end user. Add the following markup to the Index view.
@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
@Html.TextBox("name")<br /><br />
<div class="g-recaptcha"
data-sitekey="your site key goes here"></div>
<input type="submit" value="Submit" />
<strong>@Html.ValidationSummary()</strong>
}
Notice the above markup carefully. The markup consists of a <div> element
with two attributes. The class attribute is set to g-recaptcha. This way the
reCaptcha library can easily figure out the div for rendering the reCaptcha. The
data-sitekey attribute is a custom data attribute that holds the value of your
Site Key. Replace it with your actual site key before you go ahead.
The form renders a textbox where use can enter name. There is also a Submit
to submit the form. Finally, a ValidationSummary helper is used to display
validation errors if any.
Step 5 - Grab the reCaptcha response on the server
If you run the page now, you will see a reCaptcha rendered at the specified
location. However, no verification is yet wired. So, even if reCaptcha is
unsolved the form can be posted to the server the server side code (Index POST
action in this example) will get executed. This is, of course, not what we
expect.
In order to validate the reCaptcha response you first need to capture it.
reCaptcha response is basically an encrypted form field that is automatically
inserted in the page's payload. This response can be retrieved on the server
like this :
[HttpPost]
public ActionResult Index(string name)
{
string captchaResponse =
Request.Form["g-Recaptcha-Response"];
// some code here
return View();
}
Notice how the reCaptcha response is retrieved using the Request's Form
collection. The field through which the response is sent to the server is named
g-Recaptcha-Response. You need this captchaResponse value in the next step.
For ASP.NET Core the response can be retrieved as follows :
string captchaResponse =
HttpContext.Request.Form["g-Recaptcha-Response"];
For Web Forms project you will have similar code in the click event handler
of the Submit button.
Step 6 - Validate the reCaptcha response
This is probably the most important step because this is where you decide
whether the end user solved the captcha successfully or not. You have the
encrypted captcha response from Step 5, you also have private Secret Key from
Step 1. Now, it's time to use them to validate the captcha.
In order to complete this step you need to make a POST request to the
following URL :
https://www.google.com/recaptcha/api/
siteverify?secret=key_here&response=response_here
Notice how the secret and response query string parameters need to be
appended to the URL.
Upon making the POST request you will be returned a JSON result that includes
the following details :
- Success indicator flag.
- Host name.
- Time stamp in ISO format.
- Error messages if any.
How do you accomplish this step in ASP.NET?
You can make use of classes such as HttpClient or WebClient to make the POST
request. You will then need to grab the JSON response and convert into a C#
object. This can be done using Json.Net component. The HttpClient us available
to Web Forms, ASP.NET MVC, and also to ASP.NET Core. The WebClient is available
only to Web Forms and ASP.NET MVC projects. So, we will use HttpClient here.
Before we discuss how these objects can be used, let's do some preliminary
work. Add two classes in the ReCaptchaV2 folder you created earlier -
ReCaptchaValidationResult and ReCaptchaValidator. The former class holds the
result of the validation (that JSON thing I explained earlier). The latter class
contains a single static method - IsValid() - that does the POSTing part
explained earlier.
The ReCaptchaValidationResult class is shown below:
public class ReCaptchaValidationResult
{
public bool Success { get; set; }
public string HostName { get; set; }
[JsonProperty("challenge_ts")]
public string TimeStamp { get; set; }
[JsonProperty("error-codes")]
public List<string> ErrorCodes { get; set; }
}
The ReCaptchaValidationResult class consists of four properties - Success,
HostName, TimeStamp, and ErrorCodes. Notice the use of [JsonProperty] attribute
of Json.Net component that maps a JSON property to a C# property. Also, note
that ErrorCodes is a List property since there could be more than one error
messages returned during the validation process.
The skeleton of ReCaptchaValidator class is shown below :
public class ReCaptchaValidator
{
public static ReCaptchaValidationResult
IsValid(string captchaResponse)
{
//code goes here
}
}
The IsValid() method accepts the captcha response obtained in Step 5 and
returns a ReCaptchaValidationResult object to the caller.
Now, let's discuss what goes inside the IsValid() method. The following code
shows how HttpClient component can be used to make the POST request. Make sure
to replace your private Secret Key in this code.
public static ReCaptchaValidationResult IsValid
(string captchaResponse)
{
if (string.IsNullOrWhiteSpace(captchaResponse))
{
return new ReCaptchaValidationResult()
{ Success = false };
}
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://www.google.com");
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>
("secret", "your_secret_key_here"));
values.Add(new KeyValuePair<string, string>
("response", captchaResponse));
FormUrlEncodedContent content =
new FormUrlEncodedContent(values);
HttpResponseMessage response = client.PostAsync
("/recaptcha/api/siteverify", content).Result;
string verificationResponse = response.Content.
ReadAsStringAsync().Result;
var verificationResult = JsonConvert.DeserializeObject
<ReCaptchaValidationResult>(verificationResponse);
return verificationResult;
}
The code checks whether captchaResponse parameter is emptyl or otherwise. If
it's empty we return a ReCaptchaValidationResult object with Success property
set to false.
Then we create an instance of HttpClient and set its BaseAddress property. We
need to pass secret and response values in the URL encoded form as a part of the
POST request. So, we use FormUrlEncodedContent class to do just that. The
FormUrlEncodedContent class basically accepts a KeyValuePair objects for the
required URL encoded values.
We then call PostAsync() method to make a POST request to the specified URL.
The FormUrlEncodedContent object is also passed along with the request.
The result will be a JSON string and it is read using the ReadAsStringAsync()
method.
This JSON string needs to be converted to ReCaptchaValidationResult object.
This is done using JsonConvert's DeserializeObject() method. The resultant
ReCaptchaValidationResult object is returned to the caller.
Step 7 - Show error message to the end user (if any)
Now that you have validation code in place, let's use the IsValid() method
and also make an arrangement to emit the error message (if any) onto the Index
view. Modify the Index() POST version as shown below :
[HttpPost]
public ActionResult Index(string name)
{
string captchaResponse =
Request.Form["g-Recaptcha-Response"];
ReCaptchaValidationResult result =
ReCaptchaValidator.IsValid(captchaResponse);
if(!result.Success)
{
foreach (string err in result.ErrorCodes)
{
ModelState.AddModelError("", err);
}
}
return View();
}
Here, we call the IsValid() method by passing the captcha response. If the
Success property of ReCaptchaValidationResult is false then we add model errors
using AddModelError() method of ModelState. This way the validation summary
helper on the Index view will display the error messages.
The following figure shows a sample erroneous run of the captcha.
That's it for now! Keep coding!!