devise使用人机验证

目前主流的验证码形式有以下几种:

  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

相关推荐