devise使用人機驗證

董志欽發表於2018-04-26

目前主流的驗證碼形式有以下幾種:

  1. 問答題
  2. 照片驗證碼
  3. 圖片驗證碼

第一種比較直接,它主要的問題是需要儲存大量的資料,理論上題庫越大越難以破解。這裡有一個實現humanizer
第二種是利用現實中的照片,人類識別照片很容易,機器卻很難。這類方案最出名的還是Google推出的recaptcha服務recaptcha就是基於它的一個實現。
第三種是根據提供的字元組合,生成一張圖片,然後驗證使用者的輸入來判斷是不是人類。這裡介紹的是第三種,simple_captcha2

simple_captcha2

首先準備好一個安裝devise的專案。
執行rails g devise:controllers users
rails g devise:views users
編輯config/rout.rb

Rails.application.routes.draw do
  devise_for :users,controllers: {sessions: `users/sessions`}
  ...
end

gem

gem `simple_captcha2`, require: `simple_captcha`
執行bundle install

rails generate simple_captcha [template_format] # Available options erb, haml. Default: erb
rake db:migrate # Mongoid: skip this step and remove the migration

也可以直接放在application_controllers.rb中。

html

views/users/sessions/new.html.erb的form表單中新增圖片驗證:

  <%= f.input :captcha do %>
    <%= show_simple_captcha %>
  <% end %>

controller

controllers/users/session_controllers.rb中新增

include SimpleCaptcha::ControllerHelpers

重寫create:

  def create
    if simple_captcha_valid?
      super
    else
      flash[:alert]="Captcha code is wrong,try again!"
      self.resource=resource_class.new(sign_in_params)
      respond_with_navigational(resource){render :new}
    end
  end

測試

這時候重新整理頁面就可以看見有驗證碼欄位,可能會出現的問題是,會出現translation error,可以設定en.yml

en:
  hello: "Hello world"
  simple_captcha:
    label: "Enter numbers.."
    placeholder: "Type here.."

還會出現一個問題是當輸入錯誤的驗證碼進行登入時會提示驗證碼錯誤(flash),但重新整理頁面時會直接登入成功,這裡的機制是其實devise跳過了simple_captcha2的驗證結果直接登入成功了,但是頁面由於respond_with_navigational(resource){render :new}的原因沒有跳轉過去。 這樣顯然不是我們要的,應該讓simple_captcha2的驗證起作用。

方法一

sessions_controller.rb中新增
skip_before_filter :require_no_authentication, :only => [:new,:create]
當輸錯驗證碼,重新整理頁面時,頁面崩潰,提示錯誤:

ActionController::InvalidAuthenticityToken in Users::SessionsController#create
ActionController::InvalidAuthenticityToken
Extracted source (around line #195):
def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end
end
end

方法二

把驗證放在create之前,新增程式碼:

prepend_before_filter :captcha_valid,:only=> [:create]
...

private
  def captcha_valid
    if simple_captcha_valid?
      true
    else
      flash[:alert]="Captcha code is wrong,try again!"
      self.resource=resource_class.new(sign_in_params)
      respond_with_navigational(resource){render :new}
    end
  end

參考

[Devise 加上 simple_captcha2做驗證碼驗證](
https://blog.csdn.net/qwbtc/a…

完美的 Ruby 圖形驗證碼 Gem

相關文章