Does anyone have a full implementation demo of reCaptcha V3 in ASP.NET?
I found this article: Google Recaptcha v3 example demo
At the moment I am using reCaptcha V2 with the following code:
public bool RecaptchaValidate()
{
string Response = Request.Form["g-recaptcha-response"];//Getting Response String Append to Post Method
bool Valid = false;
//Request to Google Server
var CaptchaSiteKey = Settings["NewUserRegCaptchaSecretSiteKey"].ToString();
HttpWebRequest req = (HttpWebRequest)WebRequest.Create
(" https://www.google.com/recaptcha/api/siteverify?secret=" + CaptchaSiteKey + "&response=" + Response);
try
{
//Google recaptcha Response
using (WebResponse wResponse = req.GetResponse())
{
using (StreamReader readStream = new StreamReader(wResponse.GetResponseStream()))
{
string jsonResponse = readStream.ReadToEnd();
JavaScriptSerializer js = new JavaScriptSerializer();
ReCaptchaObject data = js.Deserialize<ReCaptchaObject>(jsonResponse);// Deserialize Json
Valid = Convert.ToBoolean(data.success);
}
}
return Valid;
}
catch (WebException ex)
{
throw ex;
}
}
On the view.ascx page I have:
<%@ Register TagPrefix="recaptcha" Namespace="Recaptcha" Assembly="Recaptcha" %>
<script src='https://www.google.com/recaptcha/api.js'></script>
<scrip>
var recap = grecaptcha.getResponse();
if (recap.length == 0) {
$("#verifyhuman").css("display", "block");
}
</script>
<div class="g-recaptcha" data-sitekey="<%=ReCaptchaPublicKey%>" id="recaptcha" data-callback="recaptchaCallback"></div>
The accepted answer isn't following the Google's spec for sending the response and checking the action. Its Http requests will exhaust the number of sockets also. This is my implementation.
Browser
// Could be called from an event or another piece of code.
function FunctionToCall(term) {
// Google reCaptcha check
grecaptcha.ready(function() {
grecaptcha.execute(reCaptchaSiteKey, {action: "search"}).then(function(token) {
// You can take the response token Google returns, check it server side using
// the GoogleReCaptcha class and respond with a pass or fail. If a pass, run a block of code client side.
// { ... block of code ... }
// Or if you want to secure an endpoint that your sending request too.
// Send the response token with the request to your endpoint and check the response token server side and respond with a pass or fail.
// Use the repsonse to show a message or redirect site, etc
});
});
}
Server
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class GoogleReCaptcha
{
public class ReCaptchaResponse
{
public bool success { get; set; }
public double score { get; set; }
public string action { get; set; }
public DateTime challenge_ts { get; set; }
public string hostname { get; set; }
[JsonProperty("error-codes")]
public List<string> error_codes { get; set; }
}
public static async Task<(ReCaptchaResponse Response, bool HasPassed)> ReCaptchaPassed(string secretKey, string gRecaptchaToken, string expected_action)
{
try
{
// validate
if (string.IsNullOrWhiteSpace(secretKey) || string.IsNullOrWhiteSpace(gRecaptchaToken) || string.IsNullOrWhiteSpace(expected_action))
return (null, false);
// we use HttpClientFactory to avoid exhausting number of sockets available
var httpClient = HttpClientFactory.Create();
var verifyUrl = "https://www.google.com/recaptcha/api/siteverify";
var parameters = new Dictionary<string, string>
{
{"secret", secretKey},
{"response", gRecaptchaToken}
//{"remoteip", "ip" } <= this is optional
};
using (HttpContent formContent = new FormUrlEncodedContent(parameters))
{
using (var response = await httpClient.PostAsync(verifyUrl, formContent).ConfigureAwait(false))
{
// check HTTP response code
if (response.StatusCode != HttpStatusCode.OK)
return (null, false);
// get reCaptcha response
string gRecaptchaJsonresult = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(gRecaptchaJsonresult))
return (null, false);
// check reCaptcha response is successful
var recaptcha_response = JsonConvert.DeserializeObject<ReCaptchaResponse>(gRecaptchaJsonresult);
if (recaptcha_response == null)
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha response is null" }, DefaultLogValues);
return (recaptcha_response, false);
}
if (!recaptcha_response.success)
{
var errors = string.Join(",", recaptcha_response.error_codes);
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha error codes:\n{errors}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// check reCaptcha response action
if (recaptcha_response.action.ToUpper() != expected_action.ToUpper())
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha action doesn't match:\nExpected action: {expected_action} Given action: {recaptcha_response.action}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// response score
// anything less than 0.5 is a bot
if (recaptcha_response.score < 0.5)
return (recaptcha_response, false);
else
return (recaptcha_response, true);
}
}
}
catch (Exception ex)
{
//Logging.Log(ex, DefaultLogValues);
// default to false
return (null, false);
}
}
}
You would call it like so..
var reCaptchaTask = GoogleReCaptcha.ReCaptchaPassed(Settings.GoogleReCaptcha.secret_key, SearchReq.gRecaptchaToken, "search");
Make sure to put your keys in a settings file and not in the code.