Jetpack 表單加入 Google reCAPTCHA v3 AJAX 保護免外掛,非 WordPress 也適用

使用 WordPack 免外掛方式,在 Jetpack 表單加入 Google reCAPTCHA v3 保護機制,以分數驗證我不是機器人並搭配 AJAX 即時判斷,也適一般非 WordPress 網站。
Google reCAPTCHA v3
註冊
進入 Google reCAPTCHA 管理頁面,並以下圖新增 reCAPTCHA v3。

Google 提供 reCAPTCHA 類型兩種方式:
- eCAPTCHA v3:以分數驗證要求,完全不須用戶做什麼就能自動判斷您是人類 or 機器人 (也是我們要用的類型)。
- eCAPTCHA v2:以問題驗證要求。
接著可設定此次 reCAPTCHA 能夠使用的整個網域 or 單個子網域。


查看前端金鑰;後端密鑰
點擊【設定】。

就能看到剛新增 reCAPTCHA v3 的前端金鑰;後端密鑰。

WordPress
/wp-content/themes/[theneName]/.footer.php 載入 Google reCAPTCHA 的 JavaScript:
《參考:reCAPTCHA v3 | Google Developers》
<!-- 以上省略 -->
<!-- 引用 JS -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<?php wp_footer(); ?>
</body>
</html>
Jetpack
後台新增 Jetpack 表單頁面。


查看表單送出按鈕以此 class 名稱,讓後續 JavaScript 能夠取得該按鈕。

程式
《參考:reCAPTCHA v3 | Google Developers》
前端 JavaScript
以該 WordPress 網站僅「需求洽詢」須使用 Google reCAPTCHA v3,先將 reCAPTCHA v3 規定的值加入至 Jetpack 送出表單按鈕,並以 AJAX 方式先向後端 PHP 取得 reCAPTCHA v3 驗證分數來判斷是人類 or 機器人:
- 人類:送出表單。
- 機器人:無法送出表單,須重新整理頁面,再送出表單。
// 僅「需求洽詢」頁面
if (/page-id-8623/.test(document.body.className)) {
// 取得 Jetpack 送出表單 <button>
var button = document.querySelector('.wp-block-button__link');
/**
* reCAPTCHA v3 | Google Developers https://developers.google.com/recaptcha/docs/v3#automatically_bind_the_challenge_to_a_button
*/
// 將 reCAPTCHA v3 規定的值加入至 Jetpack 送出表單 <button>
button.className = button.className + ' g-recaptcha';
button.dataset.sitekey = '前端金鑰';
button.dataset.action = 'contact';
button.dataset.callback = 'verifyCallback';
// 先停止 Jetpack 送出表單 <button> click 功能,等待 reCAPTCHA v3 回傳認證後確定非 bot 在送出
button.addEventListener('click', (event) => {
event.preventDefault();
})
function verifyCallback(token) {
let form = document.querySelector('.contact-form'); // 取得表單
let formData = new FormData();
// 要 POST 到 Server 的值
formData.append('token', token);
formData.append('action', button.dataset.action);
// Server 檔案路徑
fetch('/recaptcha-v3.php', {
method: "POST",
body: formData
})
.then(response => response.json())
.then(result => {
if(result.success) {
// 分數須大於 0.5,才當作是人類操作 (可依需求自行調整)
if(result.score >= 0.9) {
console.log('判斷為真人,送出表單');
// 判斷是真人時,送出 Jetpack 表單
form.submit();
// 分數低於 0.8,當作機器人
} else {
alert('您被判定為機器人,請重新整理網頁,再試一次。');
}
} else {
window.alert(result['error-codes'][0])
}
})
.catch(err => {
window.alert(err)
})
}
}
後端 PHP
PHP 接收【前端金鑰】並與【後端密鑰】比對是否匹配才執行驗證,將此 PHP 程式檔放置於網站根目錄下 / (這與前端 JavaScript 所發送給後端路徑有關,如欲更動,前後端須匹配):
<?php
define("RECAPTCHA_V3_SECRET_KEY", '後端密鑰');
$token = $_POST['token'];
$action = $_POST['action'];
// call curl to POST request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://www.google.com/recaptcha/api/siteverify");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array('secret' => RECAPTCHA_V3_SECRET_KEY, 'response' => $token)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$arrResponse = json_decode($response, true);
// 直接回傳,讓前端判斷
echo $response;
// or 先判斷在回傳前端
// verify the response
if($arrResponse["success"] == '1' && $arrResponse["action"] == $action && $arrResponse["score"] >= 0.5) {
// valid submission
// go ahead and do necessary stuff
} else {
// spam submission
// show error message
}
CSS 調整 reCAPTCHA v3 位置
許多網頁右下方很常放一些如回到最頂部按鈕,Google reCAPTCHA v3 圖標也在右下方,所以時常會發生重疊,因此我們可以設定 CSS 讓 Google reCAPTCHA v3 圖標變換至左下方的 CSS 如下:
《參考:How To Move The reCAPTCHA v3 badge to the left side - DiviMundo》
/* Move reCAPTCHA v3 badge to the left */
.grecaptcha-badge {
width: 70px !important;
overflow: hidden !important;
transition: all 0.3s ease !important;
left: 0px !important;
}
.grecaptcha-badge:hover {
width: 256px !important;
}
完成結果
出現 Google reCAPTCHA v3 圖標,表示此表單正受保護,即可防止機器人填表單的問題。


本著作係採用創用 CC 姓名標示-相同方式分享 3.0 台灣 授權條款授權.