読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC で reCAPTCHA を使ってみた

今更感が半端ないですが、ASP.NET MVC で開発したアプリケーションに reCAPTCHA の version 2 を組み込む方法を調べました。何番煎じか分かりませんが、小ネタ程度にまとめておきます。

reCAPTCHA を使うためには Google のサイトから URL を登録して、トークンを貰う必要があります。

reCAPTCHA: Easy on Humans, Hard on Bots

ドキュメントも数ページしかないので、これを読めば誰でも実装は出来るはずです。

Developer's Guide  |  reCAPTCHA  |  Google Developers

流れとしてはビューにタグを追加しておき、POST されたデータを API に投げて正しいかチェックするだけです。この流れは ValidateAntiForgery と似てるので、例によって Action Filter として実装します。

とりあえず作成した ValidateReCaptcha 属性のコードを丸ごと載せておきます。

public class ValidateReCaptchaAttribute : ActionFilterAttribute
{
    private const string SiteVerifyEndpoint = "https://www.google.com/recaptcha/api/siteverify";
    private const string ResponseFieldKey = "g-recaptcha-response";

    private static readonly string SecretKey = ConfigurationManager.AppSettings["ReCaptcha:SecretKey"];

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var data = new NameValueCollection
        {
            { "secret", SecretKey },
            { "response", filterContext.HttpContext.Request.Form[ResponseFieldKey] },
            { "remoteip", filterContext.HttpContext.Request.UserHostAddress }
        };

        var json = new WebClient().UploadValues(SiteVerifyEndpoint, data);

        var result = JsonConvert.DeserializeObject<ReCaptchaVerifyResponse>(Encoding.UTF8.GetString(json));

        if (!result.Success)
        {
            throw new ReCaptchaValidationException(result.ErrorCodes[0]);
        }
    }
}

public class ReCaptchaVerifyResponse
{
    public bool Success { get; set; }

    [JsonProperty("error-codes")]
    public string[] ErrorCodes { get; set; }
}

使い方の説明は要らない気がしますが、検証したいアクションに属性を付けるだけです。

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [ValidateReCaptcha]
    public ActionResult Index(FormCollection collection)
    {
        return View("Success");
    }
}

用意したビューは以下のような感じです。特に言うことはありません。

<script src="https://www.google.com/recaptcha/api.js"></script>

<h2>Index</h2>

@using (Html.BeginForm())
{
    <div class="g-recaptcha" data-sitekey="..."></div>
    <br/>
    <button type="submit">Submit</button>
}

これで準備が出来たので、実際に実行して動作を確認しておきます。ブラウザでページを表示すると、誰もが 1 回は見たことあると思われる CAPTCHA が表示されます。

f:id:shiba-yan:20160113160941p:plain

チェックを入れて Submit を行うと、検証が成功するのでページが表示されます。

f:id:shiba-yan:20160113160823p:plain

チェックを入れずに Submit を行うと、検証に失敗して例外が投げられるので、そこで処理が中断されます。

f:id:shiba-yan:20160113161019p:plain

思ったより簡単な仕組みだったので、昼休みの暇潰し程度で試せました。ASP.NET MVC 6 だと Action Filter が Task ベースになるので、HttpClient を使いたいところです。