reCAPTCHA v3 を使う際に、送信時にトークンを取得する方法についての覚書です。
reCAPTCHA v3 のガイドに掲載されている以下の例の場合、ページを読み込んですぐにトークンを取得しているので、2分後にはこのトークンの有効期限が切れてしまいます。
<script src="https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key"></script> <script> //ページ読み込み時にトークンを取得 grecaptcha.ready(function() { grecaptcha.execute('_reCAPTCHA_site_key_', {action: 'homepage'}).then(function(token) { ... }); }); </script>
以下は、送信ボタンをクリックした際にトークンを取得する例で、トークンの有効期限は送信ボタンをクリックしてから2分間になります。
以下では jQuery を使ってフォーム要素にイベントハンドラを設定し、送信時に event.preventDefault() で送信を停止してトークンを取得しています。
<html lang="ja"> <head> <title>reCAPTCHA v3 送信時にトークンを取得するサンプル</title> </head> <body> <h1>reCAPTCHA v3 sample (onsubmit)</h1> <form id="rc_form" method="post"> <button type="submit">送信</button> </form> <script src="https://www.google.com/recaptcha/api.js?render=サイトキー"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script> jQuery(function($){ $('#rc_form').submit(function(event) { event.preventDefault(); //デフォルトの動作(送信)を停止 var action_name = 'submit_sample'; //アクション名 grecaptcha.ready(function() { grecaptcha.execute('サイトキー', { action: action_name }).then(function(token) { $('#rc_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">'); $('#rc_form').prepend('<input type="hidden" name="action" value="' + action_name + '">'); $('#rc_form').unbind('submit').submit(); //submit() を実行 });; }); }); }) </script> </body> </html>
以下は PHP を使った検証(アクション名の確認とスコアが0.5以上の場合に認証)も含めたコードです。
検証を通過すると、その判定結果とスコア及び API のレスポンスを表示します。
実際の使用では検証を通過するとメールの送信などを実行します。
<?php // サイトキーとシークレットキーを記述したファイルの読み込み require 'libs/recaptcha_vars.php'; // reCAPTCHA サイトキーを変数に格納 $siteKey = V3_SITEKEY; // reCAPTCHA シークレットキーを変数に格納 $secretKey = V3_SECRETKEY; //reCAPTCHA トークン $token = isset( $_POST[ 'g-recaptcha-response' ] ) ? $_POST[ 'g-recaptcha-response' ] : NULL; //reCAPTCHA アクション名 $action = isset( $_POST[ 'action' ] ) ? $_POST[ 'action' ] : NULL; $result_status = ''; // 結果を表示する文字列を初期化 if ( $token && $action) { // トークンとアクション名が取得できれば //cURL セッションを初期化(API リクエストとレスポンスの取得) $ch = curl_init(); // curl_setopt() により転送時のオプションを設定 //URL の指定 curl_setopt($ch, CURLOPT_URL,"https://www.google.com/recaptcha/api/siteverify"); //HTTP POST メソッドを使う curl_setopt($ch, CURLOPT_POST, true ); //API パラメータの指定 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( 'secret' => $secretKey, //シークレットキー 'response' => $token //トークン ))); //curl_execの返り値を文字列にする curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //転送を実行してレスポンスを $api_response に格納 $api_response = curl_exec($ch); //セッションを終了 curl_close($ch); //レスポンスの $json(JSON形式)をデコード $result = json_decode( $api_response ); //判定 if ( $result->success && $result->action === $action && $result->score >= 0.5) { //success が true でアクション名が一致し、スコアが 0.5 以上の場合は合格 $result_status = '合格: $result->score : ' . $result->score; // 合格した場合の処理(メールの送信など)を実行 } else { // 上記以外の場合は 不合格 $result_status = '不合格'; // 不合格の場合の処理(エラーを表示するなど)を実行 } } ?> <!DOCTYPE html> <html lang="ja"> <head> <title>reCAPTCHA v3 送信時にトークンを取得するサンプル</title> </head> <body> <h1>reCAPTCHA v3 sample (onsubmit)</h1> <form id="rc_form" method="post"> <button type="submit">送信</button> </form> <div> <p>[検証結果]</p> <p><?php echo $result_status; ?></p> <p>[var_dump($resp)]</p> <pre><?php if(isset($api_response)) {var_dump($api_response);} ?></pre> </div> <script src="https://www.google.com/recaptcha/api.js?render=<?php echo $siteKey; ?>"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script> jQuery(function($){ $('#rc_form').submit(function(event) { event.preventDefault(); var action_name = 'submit_sample'; //アクション名 grecaptcha.ready(function() { grecaptcha.execute('<?php echo $siteKey; ?>', { action: action_name }).then(function(token) { $('#rc_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">'); $('#rc_form').prepend('<input type="hidden" name="action" value="' + action_name + '">'); $('#rc_form').unbind('submit').submit(); });; }); }); }) </script> </body> </html>
上記の例では API リクエストとレスポンスの取得(16行目〜33行目)には cURL関数を使用していますが、もし file_get_contents() を使う場合は以下のようになります。
//API Request URL $url = 'https://www.google.com/recaptcha/api/siteverify'; //パラメータを指定 $data = array( 'secret' => $secretKey, //シークレットキー 'response' => $_POST[ 'g-recaptcha-response' ] //トークン ); $context = array( 'http' => array( 'method' => 'POST', // POST メソッドを使う 'header' => implode("\r\n", array('Content-Type: application/x-www-form-urlencoded',)), 'content' => http_build_query($data) ) ); //上記パラメータを指定して file_get_contents でレスポンスを取得 $api_response = file_get_contents($url, false, stream_context_create($context));
詳細は以下を御覧ください。