Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

理解與前端實作 reCAPTCHA v3

內容目錄

理解與實作 recaptcha

Google reCAPTCHA 是一種常見的機器人驗證技術,用來區分人類使用者和自動化程式。現在主流有 v2 和 v3 兩種版本,是擁有免費額度的付費服務。
先前都只有透過打包好的 WordPress 外掛來實作,這次有機會在Nuxt3的前端專案中自己寫,就趁機記錄一下自己的理解與過程。

本次使用的是 reCAPTCHA v3 ,特點在於不用跟介面互動就能取得辨識結果,好處就是網站對使用者的驗證只會在背景處理,不影響使用體驗。

reCAPTCHA v3的技術原理大概可以這樣理解:

  • 行為分析:評估使用者與頁面的互動方式,如滑鼠移動模式、點擊方式和速度。
  • 瀏覽器指紋識別:收集瀏覽器和設備資訊,如作業系統、瀏覽器類型、螢幕解析度等。
  • Cookie 和歷史數據:分析用戶之前與 Google 服務的互動歷史。

實作邏輯的話,其實就是跟 reCAPTCHA 服務取用資料這樣。

前置:取得金鑰

  • 網站金鑰 (Site Key):公開的,嵌入在網頁前端代碼中
  • 密鑰 (Secret Key):私密的,只在伺服器端使用

實作流程

以下是我對 reCAPTCHA 溝通的理解:

1. 前端向 Google reCAPTCHA 請求 token

首先註冊並申請 Google reCAPTCHA 服務。
網站前端載入 reCAPTCHA SDK,當使用者執行需驗證的操作時,呼叫grecaptcha.execute(), reCAPTCHA 服務會分析使用者行為後回傳 token。

2. 前端向網站伺服器提交請求

前端將 reCAPTCHA token 連同表單數據或 API 請求一起發送給後端。

3. 伺服器向 Google reCAPTCHA 驗證 token

後端使用密鑰(secret key)向 Google reCAPTCHA API 發送驗證請求。

4. Google reCAPTCHA 返回驗證結果

JSON 格式的回應包含:
success: 驗證是否成功(true/false)
score: 闕值,人類可能性分數(0.0-1.0)
action: 觸發驗證的行為名稱
challenge_ts: 時間戳記
hostname: 網站域名

閾值判斷:

我這次使用的 reCAPTCHA v3 會回傳 0.0 到 1.0 之間的分數,此分數表示使用者行為的「人類可能性」,管理者可自行決定接受的閾值(例如 0.5)高於閾值就允許後續操作,低於則可能需要額外驗證或拒絕請求。

實作紀錄:

我使用 vue-recaptcha-v3 ,自行建立 plugin 管理與啟動 reCAPTCHA,因為只有前端實作,所以很快就處理好了。

recaptcha.client.js

import { VueReCaptcha } from 'vue-recaptcha-v3'

export default defineNuxtPlugin(async (nuxtApp) => {
  const config = useRuntimeConfig()

  // 確保 siteKey 存在並輸出調試信息
  console.log('Initializing reCAPTCHA with config:', {
    siteKey: config.public.recaptchaSiteKey,
    isDevelopment: process.env.NODE_ENV === 'development'
  })

  if (!config.public.recaptchaSiteKey) {
    console.error('reCAPTCHA site key is missing')
    return
  }

  try {
    await nuxtApp.vueApp.use(VueReCaptcha, {
      siteKey: config.public.recaptchaSiteKey,
      loaderOptions: {
        useRecaptchaNet: true, // 從 recaptcha.net 載入 script
        autoHideBadge: false,// 隱藏標籤
        explicitRenderParameters: {
          badge: 'bottomright',
          size: 'invisible'
        }
      }
    })

    // 驗證 reCAPTCHA 是否正確載入
    const recaptcha = await window.grecaptcha
    if (!recaptcha) {
      throw new Error('reCAPTCHA not loaded properly')
    }

    console.log('reCAPTCHA plugin initialized successfully')
  } catch (error) {
    console.error('Failed to initialize reCAPTCHA:', error)
  }
}) 

然後在 .env 和 nuxt.config 放好 API_KEY

例如在登入時就宣告上述的流程即可

import { useReCaptcha } from 'vue-recaptcha-v3'
const { executeRecaptcha, recaptchaLoaded } = useReCaptcha()

const handleLogin = async (e) => {

// 執行 reCAPTCHA 驗證
console.log('開始執行 reCAPTCHA 驗證')
const recaptchaToken = await executeRecaptcha('login')
console.log('recaptchaToken:', recaptchaToken)

// 發送登入請求
const response = await $fetch(`/api/login`, {
    method: 'POST',
        body: {
        account: account.value,
        password: password.value,
        recaptchaToken: recaptchaToken
        }
    })
if (response) {
//後端回傳闕值做後續處理
}

}

後端就要另外寫一隻配合密鑰的請求去詢問結果。

成功載入的話,網站會出現 reCAPTCHA 的標籤,預設在右下方。