解决Rails与SWFUpload的兼容性问题

转自:http://www.bluedash.net/spaces/%E8%A7%A3%E5%86%B3Rails%E4%B8%8ESWFUpload%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7%E9%97%AE%E9%A2%98

SWFUpload 这个工具目前非常流行,由于它支持队列上传,并支持进度显示,并可以通过Flash在客户端对文件进行验证和尺寸限制,对用户比较友好,所以很多网站都使用它做为文件上传工具。

但当它遇到Rails框架时,却出现了水土不服。由于Rails框架不再支持非Cookie的方式解析Session,导致SWFUpload在与Rails结合使用时,会出现Flash对象无法正常传递Session的情况。

因此不光是SWFUpload,所有的Flash项目在Rails框架下应用都会遇到相同的问题。当Rails网站使用 protect_from_forgery 进行保护时,如果不能正确地传递Session数据,那么Rails将会报错:ActionController::InvalidAuthenticityToken

这是由于Rails框架取不到Session数据里面的认证信息造成的。一个粗糙的解决方法是在 Controller 的一开始加入下面的代码:skip_before_filter :verify_authenticity_token, :only => [...

但这样做等于是打开了某些方法的后门,形成安全漏洞。更标准的解决办法应该是利用Rails的Rack Middleware机制,将Flash对象的数据传输过程注入Session。详细过程如下:

首先在 app 目录下建立 middleware/flash_session_cookie_middleware.rb

 

require 'rack/utils'
class FlashSessionCookieMiddleware
def initialize(app, session_key = '_session_id')
@app = app
@session_key = session_key
end

def call(env)
if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
env['HTTP_COOKIE'] = [ @session_key, params[@session_key] ].join('=').freeze unless params[@session_key].nil?
env['HTTP_ACCEPT'] = '*/*'
end
@app.call(env)
end
end

 

仔细阅读的话,代码很容易理解,当检测到HTTP通讯为Flash对象时,从 QUERY_STRING 中取得Session ID,并将相关Cookie数据注入。

接下来是使这个Middleware生效,在 environment.rb 中添加如下代码:config.load_paths += %W(#{RAILS_ROOT}/app/middleware)

使得这个Middleware在启动时加载。这样当我们在使用SWFUpload时,把Session ID通过查询字串传入即可:upload_url: "/your_url?_your_session<%=cookies[:_your_session]%>&authenticity_token=<%=form_authenticity_token.inspect%>

其中 _your_session 是网站Session的特征串,可在 initializers/session_store.rb 中查到。

1 本文中用到的 FlashSessionCookieMiddleware 来自于 http://thewebfellas.com/blog/2008/12/22/flash-uploaders-rails-cookie-based-sessions-and-csrf-rack-middleware-to-the-rescue ,稍有修改。

2 感谢刘必胜先生为本文的撰写提供技术帮助。

 

高版本rails参见:http://metautonomo.us/2010/07/09/uploadify-and-rails-3/

posted @ 2010-11-12 13:32  lib  阅读(1231)  评论(0编辑  收藏  举报