6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

reCAPTCHA Invisible 1画面で複数のrecaptchaがある時に別々のcallbackを実行

Last updated at Posted at 2017-09-24

ボットからサイトを守るための仕組みを提供してくれる、googleのサービス、reCAPTCHAについて調べたのでメモ。

今回調べたのは、reCAPTCHAのinvisible。1画面で複数のrecaptchaが必要なケースをrailsで実装します。※画面側については、基本的にはjavascriptなので言語関係なく使える内容になっていると思います。

導入手順

公式サイトを参考。キーを発行するだけ。数分で終わります。
「sign up for an API key pair」のリンクからキーを発行
https://developers.google.com/recaptcha/intro

実装方法

3つあります。
https://developers.google.com/recaptcha/docs/invisible
・Automatically bind the challenge to a button
・Programmatically bind the challenge to a button
・Programmatically invoke the challenge.

今回は、「Programmatically invoke the challenge」でやっています。
理由は、1画面で複数のrecaptchaが必要な時でも対応できるようにするため。
詳細は以下をみていただければわかるかもしれません。

recaptchaをverify(検証)するまでの流れ

1. 画面にrecaptchaを埋め込む
2. google側にリクエストを送信。(grecaptcha.execute)
3. 2.のレスポンスを受け取る。レスポンスの中のtokenが、g-recaptcha-responseという画面フィールドにセットされる。
4. g-recaptcha-responseにセットされているtokenを検証してボットかどうか判断。

実装

View

view

<! --
// 1画面にformAとformBがある場合
// formAとformBにそれぞれあるSubmitボタン(POST)で別々の処理をさせたい
-->

<form id="form-a">
<div class="g-recaptcha" data-callback="formASubmit"></div>
<button type="button" onclick="grecaptcha.execute($('#form-a').find('.g-recaptcha').data('recaptcha-widget-id'));">A_OK</button>
</form>

<form id="form-b">
<div class="g-recaptcha" data-callback="formBSubmit"></div>
<button type="button" onclick="grecaptcha.execute($('#form-b').find('.g-recaptcha').data('recaptcha-widget-id'));">B_OK</button>
</form>

<!-- callback関数を定義 -->
<script type="text/javascript">
// grecaptcha.executeを実行すると対応するcallbackが呼ばれる
// recaptcha callback formA
    function formASubmit(token) {
            $('#form-a').submit();
    }

// recaptcha callback formB
    function formBSubmit(token) {
            $('#form-b').submit();
    }
</script>

 <!--
// 以下に記載の箇所は、後に記載するgemを使用する場合、invisible_recaptcha_tagsをオーバーライドして定義しても思います。
// その場合 <%= invisible_recaptcha_tags %> とView側で定義するだけでOKです。
-->
<!-- recaptchaをレンダリング -->
<script src="https://www.google.com/recaptcha/api.js?onload=recaptchaCallback&render=explicit" async defer></script>
<script type="text/javascript">
    var captchaWidgetIds = [];
    var recaptchaCallback = function() {
        // g-recaptchaクラスの箇所にrenderします。
        $('.g-recaptcha').each(function(index, el) {
            // sitekeyはgoogle側で発行したものを指定
            // badgeはrecaptchaのロゴを表示する位置
            // callbackはinvisible recaptchaでは必須。 $(el)としているのは、1画面で複数recaptchaがあり、別名のcallbackを呼べるようにするため
            var widgetId = grecaptcha.render(el, {'sitekey' :'xxxxxxxx','size' : 'invisible','badge' : 'inline', 'callback' : $(el).data('callback')});
            $(el).data('recaptcha-widget-id', widgetId);
            captchaWidgetIds.push(widgetId);
        });
    };
</script>

画面からGETする時の場合

フォームからpostではなくgetする時
    // recaptcha callback
    function onSubmit(token) {
        window.location.href = "http://test" + "?g-recaptcha-response=" + token;
    }

Controller

gemを使う
https://github.com/ambethia/recaptcha

controller
 def verifyRecaptchaToken
    @model = Model.new

    # gemが提供しているメソッド。
    # tokenを検証し問題があれば@modelにセットします
    verify_recaptcha(model: @model)

    # @modelをみてverify結果を確認
    if @model.errors.empty?
       return true
    else
       return false
    end
  end
参考_上記の処理をgemを使わず頑張って書くと多分こんな感じ・・・
  def verifyRecaptchaToken
    token = params[:"g-recaptcha-response"]
  # googleに問い合わせた結果のtokenを検証する
  # @return [Boolean] verifyが成功すればtrue、そうで無いならfalse
    url = "https://www.google.com/recaptcha/api/siteverify"
    response =Net::HTTP.post_form URI(url),
                             {"secret":"xxxxxx", "response":token}
    if response.code == '200'
      result = JSON.parse(response.body)['success']
    else
      result = false
    end
    return result
  end

以上です。
シンプルな作りであれば実装方法で挙げた3つの方法のうち、他の2つの方法が簡単です。
ただし1画面で複数recaptchaを使用したい場合は、今回記載した方法にしておくと良いと思います。

6
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?