redmineにgoogle_reCAPTCHA(v2)を導入する

要点

  1. 便利なプラグインがある(ambethia/recaptcha
  2. google recaptchaのメニュー右上「v3 admin console」から登録
  3. config(config/initializers/recaptcha.rb)の追加
  4. app/views/account/login.html.erbの修正
  5. app/controllers/account_controller.rbの修正

経緯

だいぶ昔にチケット管理を導入しようとして挫折した。
しかし、今は人も増えて、やることも増えてきた。
プロジェクトで使ってると便利とのことで、ようやく重い腰を上げて
redmineを導入しようとしてます。

外部からも入れるようにしたいけどbasic認証では心もとない。
ということでgoogle recaptchaを入れたログです。
先にかっこ悪く言い訳をする。
違ってたらすんません。「お問い合わせ」から教えて下さい。

環境

OS:CentOS7
DB:mysql  Ver 14.14 Distrib 5.7.31
Redmine version             4.1.1.stable
Ruby version                   2.5.5-p157 (2019-03-15) [x86_64-linux]
Rails version                   5.2.4.2

google reCaputchaの登録

  1. google recaptchaのメニュー右上「v3 admin console」から登録
    今回は「v2非表示」を登録した。プラグインのREADMEを読むとV3も出来そうです。
  2. site_keyとsecret_keyをメモしておく

プラグインのインストール

https://github.com/ambethia/recaptcha
を使わせてもらいました。ありがとうございます。

 

  1. {redmine_root}/Gemfileに以下を追加
    gem “recaptcha”, require: “recaptcha/rails”
  2. $ bundle install

configの追加

config/initializers/recaptcha.rbを追加

config/initializers/recaptcha.rbRecaptcha.configure do |config|
  config.site_key = ENV['RECAPTCHA_PUBLIC_KEY']
  config.secret_key = ENV['RECAPTCHA_PRIVATE_KEY']
end

ここらへんは公式のREADMEを読んでください
※googleの公開鍵と秘密鍵は直書きせずに.envに書くなりなんなりしましょう。

viewの修正

app/views/account/login.html.erbの25行目前後を修正

  <input type="submit" name="login" value="<%=l(:button_login)%>" tabindex="5" id="login-submit" />

<%= invisible_recaptcha_tags text: l(:button_login) , name: "login", id: "login-submit", tabindex: "5" %>

※google側で「v2非表示」を選んでいるため「invisible」を選択した

Controllerの修正

app/controllers/account_controller.rbの219行目前後password_authenticationを修正


# Valid user

if user.active?


# Valid user

if verify_recaptcha(model:user) && user.active?

補足

少しハマったのでメモ。
最初、controller側でverify_recaptchaを呼び出した後に
再度「https://www.google.com/recaptcha/api/siteverify」にPOSTで
“g-recaptcha-response”を投げ直さないといけないのかと思っていた。

結論からいうとverify_recaptchaを1回呼ぶだけで良い。
siteverifyに投げても

response.body: {
  “success”: false,
  “error-codes”: [
“timeout-or-duplicate”
  ]
}
が返ってきます。