This time the implementation of the reCAPTCHA for ASP.NET MVC. We need an HTML helper:
/// <summary>
/// Extension dla recaptcha
/// </summary>
/// <remarks>
/// https://developers.google.com/recaptcha/docs/display
/// </remarks>
public static class CaptchaHtmlHelper
{
// private and public keys are read from appsettings but
// feel free to modify it so that is suits your needs
private static string CaptchaPrivateKey
{
get
{
return ConfigurationManager.AppSettings["recaptchaPrivate"];
}
}
private static string CaptchaPublicKey
{
get
{
return ConfigurationManager.AppSettings["recaptchaPublic"];
}
}
public static MvcHtmlString GenerateCaptcha(
this HtmlHelper htmlHelper )
{
TagBuilder script = new TagBuilder( "script" );
script.MergeAttribute( "src", "https://www.google.com/recaptcha/api.js?hl=pl" );
script.MergeAttribute( "async", "true" );
script.MergeAttribute( "defer", "true" );
TagBuilder div = new TagBuilder( "div" );
div.MergeAttribute( "class", "g-recaptcha" );
div.MergeAttribute( "data-sitekey", CaptchaPublicKey );
return new MvcHtmlString(
script.ToString( TagRenderMode.Normal ) +
div.ToString( TagRenderMode.Normal ) );
}
}
and an auxiliary validation attribute
/// <summary>
/// Captcha validation
/// </summary>
/// <remarks>
/// https://developers.google.com/recaptcha/docs/verify
/// </remarks>
public class CaptchaValidatorAttribute : ActionFilterAttribute
{
public class APIResponse
{
public bool success { get; set; }
public string[] error_codes { get; set; }
}
private const string RESPONSE_FIELD_KEY = "g-recaptcha-response";
public override void OnActionExecuting( ActionExecutingContext filterContext )
{
try
{
var query = HttpUtility.ParseQueryString( string.Empty );
query["secret"] = ConfigurationManager.AppSettings["recaptchaPrivate"];
query["response"] = filterContext.HttpContext.Request.Form[RESPONSE_FIELD_KEY];
HttpClient client = new HttpClient();
client.BaseAddress = new Uri( "https://www.google.com/" );
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue( "application/json" ) );
HttpResponseMessage httpresponse =
client.GetAsync( string.Format( "recaptcha/api/siteverify?{0}", query.ToString() ) ).Result;
var response = httpresponse.Content.ReadAsAsync<APIResponse>().Result;
// this will push the result value into a parameter in our Action
filterContext.ActionParameters["captchaValid"] = response.success;
base.OnActionExecuting( filterContext );
}
catch ( Exception ex )
{
filterContext.ActionParameters["captchaValid"] = false;
}
}
}
The validation attribute uses the HttpClient, make sure you reference the Microsoft.AspNet.WebApi.Client package.
To use the extension, place it in your view:
<div>
@Html.GenerateCaptcha()
</div>
and decorate your action with the validation attribute:
[HttpPost]
[CaptchaValidator]
public ActionResult TheActionName( bool captchaValid )
{
if ( ModelState.IsValid && captchaValid )
{
...