於 Laravel 專案中套用 Google reCaptcha v3

前言:
原網站是使用僅次於 Google reCaptcha 的驗證碼系統:hCaptcha。
雖說主打免費,但每次使用時都得勾選我不是機器人且一定要做圖片驗證。
使得表單功能操作上有些不直覺,故而想改為 Google reCaptcha。

而大多數 Laravel 搭配 Google reCaptcha 的教學文章都是以 package 安裝來完成。
因此本篇文章用以紀錄,如何不使用 package 來完成 Google reCaptcha 架設。

步驟 1 - 申請 Google reCaptcha:
先至以下網址申請 Google reCaptcha v3 的使用金鑰
https://www.google.com/recaptcha/admin/create?hl=zh-tw

- 類型選擇 v3 版本 -

提交後便會出現 Google reCaptcha v3 的網站金鑰及密鑰。
請先停留在此頁面,或將金鑰及密鑰複製存下來。

步驟 2 - 設定 .env 及 app.php:
於 .env 中設定以下資訊:
# true or false,於測試站時使用 false,正式站則使用 true
RECAPTCHA_ENABLE=false
RECAPTCHA_URL=https://www.google.com/recaptcha/api/siteverify
RECAPTCHA_SITE_KEY=填入網站金鑰
RECAPTCHA_SECRET_KEY=填入密鑰
在 config/app.php 中設定以下資訊:
'RECAPTCHA_ENABLE' => env('RECAPTCHA_ENABLE'),
'RECAPTCHA_URL' => env('RECAPTCHA_URL'),
'RECAPTCHA_SITE_KEY' => env('RECAPTCHA_SITE_KEY'),
'RECAPTCHA_SECRET_KEY' => env('RECAPTCHA_SECRET_KEY'),




步驟 3 - 於 Blade 版型中加入以下內容:
於表單 <form></form> 中加入以下內容:
<input type="hidden" name="google_recaptcha" id="ctl-recaptcha-token">
加入 script 內容:
<script src="https://www.google.com/recaptcha/api.js?render={{ config('app.RECAPTCHA_SITE_KEY') }}"></script>
<script>
    grecaptcha.ready(function() {
        grecaptcha.execute('{{ config("app.RECAPTCHA_SITE_KEY") }}').then(function(token) {
            document.getElementById('ctl-recaptcha-token').value = token;
        });
    });
</script> 

步驟 4 - 新增 Rule 規則:
先利用 artisan 新增一個 rule 檔案:
php artisan make:rule GoogleRecaptcha
接著至 app/Rules/GoogleRecaptcha.php 中進行以下編輯:
<?php
namespace App\Rules;
use GuzzleHttp\Client;
use Illuminate\Contracts\Validation\Rule;
class GoogleRecaptcha implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        // 若為正式站時,進行驗證。反之則直接 return true
        if (config('app.RECAPTCHA_ENABLE') == true) {
            return $this->verify($value);
        }
        return true;
    }
    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }

    // 驗證 funcation
    private function verify(string $token = null): bool
    {
        // 送 api 以進行驗證
        $url = config('app.RECAPTCHA_URL');
        $response = (new Client())->request('POST', $url, [
            'form_params' => [
                'secret' => config('app.RECAPTCHA_SECRET_KEY'),
                'response' => $token,
            ],
        ]);
        $code = $response->getStatusCode();
        $content = json_decode($response->getBody()->getContents());
        return $code == 200 && $content->success == true;
    }
}

步驟 5 - 於 Controller 或 Request 中設定 validate:
這步驟則是依照個人開發習慣,是將 validate 寫在 Controller 或者 Request 中而有所不同:

於 Controller 時加入以下內容:
$request->validate([
    ...
    'google_recaptcha' => ['required', 'string', new GoogleRecapcha()],
]);
於 Request 時在 rules() 中加入以下內容:
public function rules()
{
    return [
        ...
        'google_recaptcha' => ['required', new GoogleRecaptcha()],
    ];
}
以上兩種做法都別忘記宣告位於 Rules 中的 GoogleRecaptcha。



步驟 6 - 部署上正式站後,到對應頁面看看狀況:


於網站右下角出現 google reCaptcha 字樣代表已經成功了。
另外 Google 也有提供隱藏此標示的做法。

於 css 檔案中加入以下內容:
.grecaptcha-badge { 
    visibility: hidden;
}

便可消除 google reCaptcha 了。
到我完成的頁面去看看吧!
https://aris.tw/contact

後記:
這個網站也漸漸加入了一些 google 的服務。
除了 analytics、adsense 及本篇的 reCaptcha 之外。
其實另外還有沒套用上來的 google oauth 功能。
最初也只是玩玩看而已,還沒有想到這個網站如果開通會員功能要做什麼用途。
未來如果有相關動作後會再補上類似這樣的教學文章以供日後自己參考用。
希望這篇文章對大家有所幫助!