NOTE / Ruby-On-Rails

在Ruby 使用 recaptcha Gem 安裝驗證碼

首先在Gemfile安裝rucaptcha

gem 'rucaptcha'

建立驗證碼相關資訊touch config/initializers/rucaptcha.rb

填入以下內容作為訂製 rucaptcha

RuCaptcha.configure do
# Color style, default: :colorful, allows: [:colorful, :black_white]
# self.style = :colorful
# Custom captcha code expire time if you need, default: 2 minutes
# self.expires_in = 120
# [Requirement / 重要]
# Store Captcha code where, this config more like Rails config.cache_store
# default: Read config info from `Rails.application.config.cache_store`
# But RuCaptcha requirements cache_store not in [:null_store, :memory_store, :file_store]
# 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符
# 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store
self.cache_store = :mem_cache_store
# Chars length, default: 5, allows: [3 - 7]
# self.length = 5
# enable/disable Strikethrough.
# self.strikethrough = true
end

叫出關於user的控制器和畫面(Ruby預設為隱藏user相關控制器和VIEW)

rails g devise:controllers users
rails g devise:views users

app/controllers/users/registrations_controller.rb,輸入以下

def create
  build_resource(sign_up_params)
  if verify_rucaptcha?(resource) && resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  else
    clean_up_passwords resource
    respond_with resource
  end
end

app/views/users/registrations/new.html.erb,輸入以下

<%= rucaptcha_image_tag(alt: 'Captcha') %>
<%= rucaptcha_input_tag(class: 'form-control', placeholder: '請輸入驗證碼!') %>

最後修改config/routes.rb配置,將原本的 devise_for :users刪除用下面指令做取代

devise_for :user, controllers: {
  passwords: 'users/passwords',
  registrations: 'users/registrations',
  sessions: 'users/sessions'
}

驗證碼就安裝完成了但還需要一些額外的安裝才可以讓他正常運作 由於RuCaptcha原作者擔心將驗證碼存在Session 會存在 Replay attack 漏洞導致驗證碼會被攻破詳情可以洽官網 所以作者使用一個可以配製分布式的存續方案Ex:Memcached 或 Redis可以支援cache_store的方案 在這會使用到Memcached作為實現的功能

如果之前有安裝過 memcached 就不用在安裝了

brew install memcached
brew services start memcached

在Gemfile安裝gem 'dalli'dalli
dalli可以讓memcached變得更完善也會讓 rails性能變得更好,如果要發佈到 Heroku,請編輯/config/initializers/rucaptcha.rb
在開發端請使用預設

if Rails.env.development?
  self.cache_store = :mem_cache_store
end

編輯/config/initializers/production.rb 在正式環境啟用

if Rails.env.production?
config.cache_store = :dalli_store,
  (ENV["MEMCACHIER_SERVERS"] || "").split(","),
  {
    :username => ENV["MEMCACHIER_USERNAME"],
    :password => ENV["MEMCACHIER_PASSWORD"],
    :failover => true,
    :socket_timeout => 1.5,
    :socket_failure_delay => 0.2,
    :down_retry_delay => 60
  }
end

這樣不管在開發環境或是正式環境都可以使用到, 在使用下列這行啟用Heroku Memcache heroku addons:create memcachier:dev

REFERENCE / 3

Loading