Issue
I want add captcha in login view for my ASP.NET application. The view is quite simple has only email and password text box. Now below the email and password text box I want to add captcha in my login form.
I have look into many articles about adding captcha and found Captcha in ASP.NET MVC 5 is quite simple to use but when I added it to my app.
Instead of showing captcha image it starts displaying a cross symbol.
I have checked all the configuration already there is nothing wrong with the implementation. Is there any other easiest way to add captcha in ASP.NET app ?
Solution
Below is the full implementation from one of my latest projects – it simply follows Google’s Recaptcha guidance with some additional useful code – please check the latest Google documentation for the latest updates:
Add 2 new keys in your web.config file – one for the site key and the other for the secret key – you get these values when you register your website from the Google Recaptcha portal.
<add key="RECAPTCHA:SITE_KEY" value="Your site key that you generate from " />
<add key="RECAPTCHA:SECRET_KEY" value="Your secret key" />
Create a public static Config class to reach your web.config key values easily as follows;
public static class Config
{
private static NameValueCollection _appSettings;
private static NameValueCollection AppSettings => _appSettings ?? (_appSettings = ConfigurationManager.AppSettings);
public static string RecaptchaSiteKey => GetStringValueOrDefault("RECAPTCHA:SITE_KEY", "");
public static string RecaptchaSecretKey => GetStringValueOrDefault("RECAPTCHA:SECRET_KEY", "");
private static string GetStringValueOrDefault(string key, string defaultValue)
{
return string.IsNullOrWhiteSpace(GetStringValueFromAppSettings(key))
? defaultValue
: GetStringValueFromAppSettings(key);
}
private static string GetStringValueFromAppSettings(string key)
{
return string.IsNullOrEmpty(AppSettings[key]) ? string.Empty : AppSettings[key];
}
}
Add the g-recaptcha section to your view, i.e.
if (ViewData.ModelState.Keys.Contains("OverallError"))
{
<div class="form__row">
@Html.ValidationMessage("OverallError", new { @class = "form__error" }).Raw()
</div>
}
<div class="form__row">
<div class="form__controls">
<div class="g-recaptcha"
data-sitekey="@YourProject.Config.RecaptchaSiteKey"
data-callback="reCaptchaResponse">
</div>
@Html.HiddenFor(m => m.RecaptchaToken)
</div>
</div>
<div class="form__row form__row--final">
<div class="form__controls">
<button type="submit" class="button button--primary" id="createAccountSubmit">Create account</button>
</div>
</div>
Script section on the same view;
@section Scripts {
<script>
$(document).ready(function () {
createAccountSubmit.disabled = true;
});
var createAccountSubmit = document.getElementById("createAccountSubmit");
function reCaptchaResponse(token) {
$('#RecaptchaToken').val(token);
createAccountSubmit.disabled = false;
}
</script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
}
Add RecaptchaToken to your viewmodel;
public string RecaptchaToken { get; set; }
And here is your post action and how you can validate your recapcha token and add some custom validation errors:
if (ModelState.IsValid)
{
if (!await model.RecaptchaToken.ValidateAsRecapchaToken())
{
ModelState.AddModelError("OverallError", "CAPTCHA validation failed. Please try again.");
}
// Always clear the token as it is no longer valid. Any subsequent re-posts will need a new token.
ModelState.SetModelValue(nameof(model.RecaptchaToken), new ValueProviderResult("", "", CultureInfo.InvariantCulture));
}
StringExtension to validate the recapcha token:
public static class StringExtensions
{
public static async Task<bool> ValidateAsRecapchaToken(this string token)
{
using (var client = new HttpClient())
{
var secret = Config.RecaptchaSecretKey;
var url = $"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={token}";
var response = await client.PostAsync(url, new StringContent(""));
var responseModel = await response.Content.ReadAsAsync<RecaptchaResponseModel>();
return responseModel.Success;
}
}
}
This is how things look like:
Answered By – Nurhak Kaya
Answer Checked By – Robin (BugsFixing Admin)