edo1z blog

プログラミングなどに関するブログです

vue-cli + firebase + functions + hostingでgoogle recaptcha v3を使う

recaptchaのような動作可能なURLが限定される場合、functionsのURLは変な長いやつになりますので、どうしたらいいのかというのと、動作確認方法はどうしたらいいのかなと思いました。

hostingを使っている前提であれば非常に簡単で、下記に書いていますが、hostingのパスにfunctionsを簡単に紐付けられるので、recaptha的には、hostingのurlを通しておけば、functionsも動作するようになります。

developers-jp.googleblog.com

hostingとfunctionsのマッピング

{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "/checkRecaptcha",
        "function": "checkRecaptcha"
      }
    ]
  }
}

functionsのコード

functionsのコードは下記のようにしました。

const axios = require('axios');
const functions = require('firebase-functions');
const apiKey = functions.config().const.mailgun.api_key;
const domain = functions.config().const.mailgun.domain;
const mailgun = require('mailgun-js')({apiKey: apiKey, domain: domain, timeout: 10000});

exports.hoge = functions.https.onRequest(async (req, res) => {
  if (!req.body.name || !req.body.email || !req.body.content || !req.body.token) {
    return res.status(400).send('invalid params');
  }
  if (!recaptcha(req.body.token)) {
    return res.status(400).send('invalid token');
  }
  if (await sendMessage(req.body)) {
    return res.status(200).send({success: true, message: ''});
  } else {
    return res.status(200).send({success: false, message: ''});
  }
});

const recaptcha = async (token) => {
  const url = 'https://www.google.com/recaptcha/api/siteverify';
  const secret = functions.config().const.recaptcha.secret;
  const data = {
    secret: secret,
    response: token,
  };
  const options = {
    url: url,
    method: 'POST',
    data: data,
    headers: {
      'Content-Type': 'application/json'
    }
  };
  const result = await axios(options);
  if (result.status === 200 && result.data.success) return true;
  return false;
};

フロントのコード

フロント側は、下記を利用させていただきました。

github.com

動作確認方法

ローカルでも確認できるかもしれませんが、開発環境をデプロイして確認できます。vue-cliの場合、下記に設定方法が書いてあります。

cli.vuejs.org

これについては、下記でもメモりましたが、下記2つのファイルを用意して、環境を切り替えています。

blog.logicky.com

.env.development
.env.production

ただ、deploy時にyarn build -> firebase deployとすると、env.productionが利用されてしまいます。ですので例えば下記のような場合、

$ yarn build
$ firebase use dev
$ firebase deploy

devは、firebase.rcで下記のように設定しているもので、利用するfirebase projectを複数設定できます。devは開発環境用のfirebase projectです。

{
  "projects": {
    "dev": "hoge-dev",
    "pro": "hoge"
  }
}

devを使ってデプロイしましたので、devプロジェクトがhostingにアップされて、devプロジェクトのfunctionsがデプロイされます。 ただ、hostingされたアプリ内でもfirebaseを利用する場合、それだけは本番プロジェクトを使ってしまうという現象がおきます。 ですので、vue-cliでは下記のようにします。

package.jsonにbuild-devというscriptを追加します。

"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "build-dev": "vue-cli-service build --mode development",
  "lint": "vue-cli-service lint"
},

これで.env.developmentを使ったbuildができます。

$ yarn build-dev
$ firebase deploy --only hosting

これで、完全にdevelopment環境になります。

ちなみに、動作確認が終わって、development環境のhostingを消したい場合は、下記でできます。

$ firebase hosting:disable

f:id:edo1z:20190403130200p:plain