Xu Wenhao

View on GitHub
9 February 2009

functional tests中的form_authenticity_token

by Xu Wenhao

又是一个前一阵遇到的很tricky的问题。

Rails2.0中加入了form_authenticity_token来防止部分的cross-site的攻击,ActionView中默认的form_for标签会自动加入类似于

的代码,如果你自己使用form_tag来创建form的话,可以用类似于

<input type="hidden" name="authenticity_token" value="<%= "#{form_authenticity_token}" %>" />

的代码来加入这个隐藏的form中的authenticity_token。

但是手工加入这个token在functional tests中会带来问题,因为functional tests中是把allow_forgery_protection关掉的
可以在environments/test.rb中看到这样的配置

config.action_controller.allow_forgery_protection    = false

但是authenticity现在是hardcode在代码中,所以跑functional tests通常会遇到这样的错误

ActionView::TemplateError: No :secret given to the #protect_from_forgery call.  Set that or use a session store capable of generating its own keys (Cookie Session Store).

一种解决办法是在view中加入当前all_forgery_protection状态的判断代码,比如

<% if  protect_against_forgery? %>  
<input type="hidden" name="authenticity_token" value="<%= "#{form_authenticity_token}" %>" />  
<% end %>

但是有位同学用了个更巧妙的hook的办法,在test_helper.rb中hook掉form_authenticity_token,如下

module ActionController  
  module RequestForgeryProtection  
    def form_authenticity_token  
      return "form_authenticity_token OVERRIDE!"  
    end  
  end  
end

我比较喜欢后一种啦。

tags: