🏙️

Astro + Vercel Serverless FunctionsでのreCAPTCHA v3の導入例

2023/09/08に公開

Astroで作ったWebサイトにreCAPTCHA v3を導入する機会があったので、備忘録として残しておきます。

reCAPTCHA v3とは?

お問合せフォームでよく見かけるアレです。

フォームが設置されているページにreCAPTCHAを導入することで、スパムの送信を防ぐことができます。

また、reCAPTCHA v3ではバックグラウンドでユーザーの動きを検証しスコアを判定するので、「私はロボットではありません」のチェックボックスやイライラする画像の選択などの操作は不要になります。

https://developers.google.com/recaptcha/docs/v3

実装例

Astro + Vercel Serverless Functionsでの実装例を紹介します。
今から説明するコードは、すべて以下リポジトリにあります。

https://github.com/kawamataryo/astro-recaptcha-sampler

デモサイトもこちらで公開しているので、実際の動きも確認できます。

https://astro-recaptcha-sample.vercel.app/

1. reCAPTCHA v3の設定

reCAPTCHA v3のコンソールにて新しいサイトを登録し、サイトキーとシークレットキーを取得します。
ドメインには、reCAPTCHAを導入するサイトのドメインを入れてください。

https://www.google.com/recaptcha/admin/create

サイトキーとシークレットキーをメモしておきます。

2. Server 側での実装

Server側は、AstroのServer Endpointsを使って実装します。

src/pages/api/recaptcha.tsを作成します。

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/pages/api/recaptcha.ts#L1-L18

シークレットキーとフロントエンドから受け取ったreCAPTCHAのトークンを使って、スコアを取得しています。

3. Client 側での実装

Client側では、サイトキーをクエリパラメーターに設定した上で、reCAPTCHAのライブラリを読み込みます。

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/pages/index.astro#L9-L11

そして、送信ボタン押下時の関数内で grecaptcha.ready にてreCAPTCHAのスクリプトの読み込みを待ってから、grecaptcha.executeでトークンを取得し、それをAPIに送信、スコアを取得しています。

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/components/ContactForm.astro#L33-L67

今回のコードでは、結果のスコアをバナーの表示に使っていますが、実際の運用ではここでフォーム送信の可否を判定するといった使い方をすると思います。

以下Formの全コードです。AstroコンポーネントとReactコンポーネントの両方で実装してみました。

Astroコンポーネントでの例

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/components/ContactForm.astro#L1-L71

Reactコンポーネントでの実装例

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/components/ContactForm.tsx#L1-L101

4. Vercelへのデプロイ

Astroのリポジトリを、Vercelと連携させれば自動的にデプロイされるのですが、Server Endpointsを使う場合は事前準備が必要です。

以下をコマンドラインで実行し、AstroのVercelアダプターを追加します。

npx astro add @astrojs/vercel

astro.config.mjsを以下のように修正します。

import { defineConfig } from 'astro/config';
import vercel from "@astrojs/vercel/serverless";

import react from "@astrojs/react";
export default defineConfig({
  output: "hybrid",
  adapter: vercel(),
});

このoutput: "hybrid"という指定は、デフォルトでプリレンダリングするが、export const prerender = false;が設定されているファイルはサーバーサイドでリクエストごとにレンダリングするというものです。

https://docs.astro.build/en/reference/configuration-reference/#output

今回の例だとreCAPTCHAのAPI(pages/api/recaptcha.ts)についてはプリレンダリングしてほしくないので、ファイル先頭にexport const prerender = false;を追加しています。

https://github.com/kawamataryo/astro-recaptcha-sampler/blob/main/src/pages/api/recaptcha.ts#L1

あとは通常通りVercelにデプロイすればOKです。
静的ファイルと、Vercel Serverless Functionsがデプロイされます。

おわり 🚀

Discussion