😉

Rails recaptcha v3を導入

に公開

はじめにを読んだ

利用を開始するにはAPIキーを登録する必要がある。
開発環境用にドメインにlocal_host必要

クライアントサイドを読んで実装

headタグ

<!-- Google reCAPTCHA -->
<script src="https://www.google.com/recaptcha/api.js?render=<%= Rails.application.credentials[:recaptcha_client] %>"></script>
<script>
  document.addEventListener("turbo:load", function() {
    grecaptcha.ready(function() {
      grecaptcha.execute("<%= Rails.application.credentials[:recaptcha_client] %>", { action: アクション }).then(function(token) {
        const recaptchaResponse = document.getElementById('g-recaptcha-response-data');
        recaptchaResponse.value = token;
      });
    });
  });
</script>
<!-- // Google reCAPTCHA -->

フォーム内にhiddenフィールドを追加(nameタグがサーバサイドで使われるため注意)

<%= hidden_field_tag '#g-recaptcha-response-data' %>

turboの影響か、grecaptchaが読み取られていません。エラーになる。

サーバーサイドを読んで実装

gem 'recaptcha' を使う場合

※ 認証失敗時モデルにエラーが追加される

@model = Model.new(strong_params)
success = verify_recaptcha(model: @model, minimum_score: 0.9, secret_key: Rails.application.credentials.dig(:recaptcha_backend))
if success && @model.save
  flash[:success] = '送信が成功しました。'
  redirect_to root_path
else
  flash.now[:alert] = '送信が失敗しました'
  render :new, status: :unprocessable_entity
end

gem 'recaptcha' を使わない場合

require 'net/https'
require 'json'

uri = URI.parse('https://www.google.com/recaptcha/api/siteverify')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri.path)
req.set_form_data({
  'secret' => Rails.application.credentials.dig(:recaptcha_backend),
  'response' => params['g-recaptcha-response-data']
})

res = http.request(req)
post_result = JSON.parse(res.body)

if !post_result['success'] || post_result['score'] < 0.9
  flash.now[:alert] = 'ロボットではないことを確認できませんでした。'
  render :new, status: :unprocessable_entity
  return
end

@model = Model.new(strong_params)
if @model.save
  flash[:success] = '送信が成功しました。'
  redirect_to root_path
else
  flash.now[:alert] = '送信が失敗しました'
  render :new, status: :unprocessable_entity
end

Discussion