Vue.js で入力フォームに Google reCAPTCHA v2 を埋め込む

f:id:hamakou108:20210802213420j:plain

Vue Composition API-0.3 Nuxt-2.1 TypeScript-3.7

こんにちは。エンジニアの濱田( @hamakou108 )です。

今回は Vue.js で作成した入力フォームに Google reCAPTCHA v2 を埋め込むコードを書く機会があったので、その実装例を紹介します。 またその際に利用した vue-recaptcha というライブラリについても軽く紹介します。

はじめに

  • 本記事執筆時点では vue-recaptcha は v2 のみ対応しています。
  • reCAPTCHA へのサイトの登録、サーバーサイドでのトークンの検証に関しては本題から逸れるため割愛します。

背景

M&Aクラウドの幾つかの入力フォームでは、スパムなどの不審なリクエストへの対策として Google reCAPTCHA を導入しています。 一方、以前からフロントエンドの Nuxt.js 移行を進めており、これらのフォームについても移行を行いました。

tech.macloud.jp

旧ページで reCAPTCHA を埋め込んでいた箇所では HTML のフォームによる POST を行っていました。 この場合はドキュメントにある通り、フォーム要素内に g-recaptcha タグを埋め込むだけで事足ります。

一方、 Nuxt.js の新ページでは API による POST を使用しています。 旧ページと同じ手法は使えないため、実装方法を再検討する必要がありました。

reCAPTCHA 埋め込みの実装

vue-recaptcha の利用

先人の知恵がないかググってみたところ、 vue-recaptcha というドンピシャなライブラリがありました。

github.com

vue-recaptcha は reCAPTCHA を埋め込みたいページにコンポーネントを埋め込むだけで利用できます。 また reCAPTCHA のオプションについては v-bind で設定でき、検証の成功やエラーのイベントも v-on でハンドリングできるので便利です。

vue-recaptcha は reCAPTCHA v2 にのみ対応していますが、弊社で利用しているものも v2 のみだったため、特に問題なく採用することができました。 またフロント移行が進むにつれて reCAPTCHA を使用するフォームが増えることが予想されたため、最低限の知識で reCAPTCHA を埋め込めるようなコンポーネントを vue-recaptcha をラップして実装しました。

実装したコンポーネント

以下のようなコンポーネントを実装しました 1

<template>
  <vue-recaptcha
    ref="recaptcha"
    :sitekey="sitekey"
    size="invisible"
    :load-recaptcha-script="true"
    class="recaptcha"
    @verify="onVerify"
  ></vue-recaptcha>
</template>

<script lang="ts">
import VueRecaptcha from 'vue-recaptcha'
import { defineComponent, ref, SetupContext, toRefs, watch } from '@vue/composition-api'

export default defineComponent({
  components: {
    VueRecaptcha
  },
  props: {
    submit: {
      type: Boolean,
      default: false
    }
  },
  setup(props, { emit }: SetupContext) {
    const { submit } = toRefs(props)
    const recaptcha = ref<InstanceType<typeof VueRecaptcha> | null>(null)
    const sitekey = // サイトキーを設定
    const onSubmit = (): void => {
      if (submit.value) {
        return recaptcha.value?.execute()
      }
    }
    const onVerify = (response: any): void => {
      emit('verify', String(response))
    }
    watch(submit, onSubmit)

    return {
      recaptcha,
      sitekey,
      onVerify
    }
  }
})
</script>

<style src="./recaptcha.scss" lang="scss" scoped></style>

以下、要点を説明します。

reCAPTHCA の実行

vue-recaptcha を使って reCAPTCHA の認証を実行する際は VueRecaptcha コンポーネントexecute メソッドを呼び出します。 呼び出しタイミングをロジック側で制御したいため、 template refs を使ってコンポーネントインスタンスrecaptcha という定数に格納し、 recaptcha.value?.execute() のような形で呼び出せるようにしています。

props の submit は親コンポーネントが reCAPTCHA を呼び出したいタイミングで true に変更されることを期待しています。 submitwatch で監視しているため、 true に更新された際に onSubmit メソッドが呼び出され、 reCAPTCHA の認証が実行されます。

reCAPTCHA の認証トークンの受け取り

reCAPTCHA の認証が成功すると VueRecaptcha コンポーネントから verify イベントが emit されます。 reCAPTCHA のレスポンスも一緒に渡されるので、それを文字列に型変換して親コンポーネントに emit します。 親コンポーネントではこのレスポンスを POST API のパラメータに含めることができます。

reCAPTCHA 実行用スクリプトの埋め込み

本来は reCAPTCHA の共通的な導入手順として実行用の JavaScript<script> タグで埋め込む必要があります。 しかし vue-recaptcha には<script>タグの inject 機能があり、 props に :load-recaptcha-script="true" を渡すことで必要なタグを自動的に <head> 内に追加してくれます。

まとめ

vue-recaptcha を利用して

  1. reCAPTCHA の起動が必要なタイミングで submit props の値を true にする
  2. verify イベントで reCAPTCHA のレスポンスを受け取る

の2つの手順のみで reCAPTCHA を埋め込むことができるコンポーネントを実装しました。 Vue.js で作成した web ページに reCAPTCHA を埋め込みたい方の参考になれば幸いです。

おわりに

M&Aクラウドではデザイナーやエンジニアを募集しています! 是非お気軽にご連絡ください!

www.wantedly.com

www.wantedly.com

www.wantedly.com


  1. Vue.js の Composition API 0.3 による実装のため、バージョン 1.0 以降の記法と異なる場合があります。