Introduction
The main purpose of this tip is to show a way of using the new Google reCaptcha plugin with MVC5. I think it would cover MVC4 as well.
Background
I was working on a project which required reCaptcha and the nuget plugin which seems to be the most documented in the old version. I couldn't find much on the new plugin, so I thought I should show how I came up with a solution.
Using the Code
To start, I signed up to reCaptcha and acquired my public and secret key. I added these to the web.config file.
<appSettings>
<add key="RecaptchaPrivateKey" value="PRIVATEKEYHERE" />
<add key="RecaptchaPublicKey" value="PUBLICKEYHERE" />
</appSettings>
I then set out to display the reCaptcha plugin using an HtmlHelper
extension. I pulled the public key from the web.config and sent back the HTML string.
public static class HtmlHelpers {
public static IHtmlString reCaptcha(this HtmlHelper helper) {
StringBuilder sb = new StringBuilder();
string publickey = WebConfigurationManager.AppSettings["RecaptchaPublicKey"];
sb.AppendLine("<script type=\"text/javascript\"
src='https://www.google.com/recaptcha/api. js'></script>");
sb.AppendLine("");
sb.AppendLine("<div class=\"g-recaptcha\"
data-sitekey=\""+ publickey+"\"></div>");
return MvcHtmlString.Create(sb.ToString());
}
}
In the View, I wanted to display the reCaptcha I just used.
<div class="editor-label">
Are you a human?
</div>
<div class="editor-field">
@Html.reCaptcha()
</div>
I then created a new class inheriting from ActionFilterAttribute
so I could capture the response code, send the web request and add the response to the action parameters.
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.RequestContext.HttpContext.Request["g-recaptcha-response"] != null) {
string privatekey = WebConfigurationManager.AppSettings["RecaptchaPrivateKey"];
string response = filterContext.RequestContext.HttpContext.Request["g-recaptcha-response"];
filterContext.ActionParameters["CaptchaValid"] = Validate(response, privatekey);
}
}
I built the Validate
function which handles the request and the Json response using Newtonsoft.Json
with a bespoke object for the request.
public static bool Validate(string mainresponse, string privatekey) {
try {
HttpWebRequest req = (HttpWebRequest)WebRequest.Create
("https://www.google.com/recaptcha/api/siteverify?secret=" +
privatekey + "&response=" + mainresponse);
WebResponse response = req.GetResponse();
using (StreamReader readStream = new StreamReader(response.GetResponseStream())) {
string jsonResponse = readStream.ReadToEnd();
JsonResponseObject jobj = JsonConvert.DeserializeObject<JsonResponseObject>(jsonResponse);
return jobj.success;
}
}
catch (Exception) {
return false;
}
}
public class JsonResponseObject {
public bool success { get; set; }
[JsonProperty("error-codes")]
public List<string> errorcodes { get; set; }
}
Then, I add the RecaptchaFilter
to the FilterConfig
so the check for the capture is done on all ActionResults
.
filters.Add(new RecaptchaFilter());
Then, I just added the CaptchaValid
parameter to my controller and set up my condition.
public ActionResult MyController(MyModel model, bool CaptchaValid) {
if (!CaptchaValid) {
ModelState.AddModelError("reCaptcha", "Invalid reCaptcha");
return View(model);
}
else {
return View();
}
}
Points of Interest
When importing the correct usings for ActionFilterAttribute
for the RecaptchaFilter
, use using System.Web.Mvc;
NOT using System.Web.Http.Filters;
Remarks
The project included is a fully working example, provided a Private & Public key has been added to the web.config.