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));
詳細は以下を御覧ください。