解决Ruby On Rails下使用SwfUpload等Flash上传组件取不到Session

最近刚做好一个站,rails 3,大家捧场看看,谢谢!www.yo945.com

  

SwfUpload相当的好用,在让我在写前台功能的时候,是相当的爽快,然后写后台,OK,相当相当的爽快,相当相当的给力,可同时上传N个文件,显示进度,上传完成支持回调,相当好用!可是,当我在给后台加上用户登录验证时,发现居然取不到session了?!无论如何也取不到!相当相当的郁闷了……

  分析了一下,主要原因是因为Rails为了安全,启用了CSRF验证,而SwfUpload因为FLASH对于安全设置的要求,又不允许随意设置HTTP头,而且默认也是不加上cookie的,所以导致上传时没有cookie也没有session_id。

  解决之道,就是要让SwfUpload带上该带的数据,又要让Rails通过验证,具体作法,记录如下。

  首先,如果本次操作是必须要有cookie中带的信息的,那么先要让swfuplod带上cookie信息,这步不是必须的,看个人需要,做起来也是相当的简单,因为在下载下来的SWFUpload v2.2.0.1 Core中,本身就带了一个pluggin,就是plugins\swfupload.cookies.js,引用的时候先引用swfupload组件,再引用swfupload.cookie.js即可,不有再做任何额外操作,在提交时自动就会带上cookie信息。加上这个插件后,swfuplod多了一个方法,就是refreshCookies,功能么一看函数名就知道了。插件的原理很简单,就是读取document.cookie然后给swfupload的post_params设置值而已,所以如果嫌它写得麻烦,自己设置一下也是很简单的。

  第二步,给post_params加上两个必须属性,这是关键一步。第一个参数,就是CSRF的值,第二个参数,就是session_id值。大致上,可以这样写,先通过服务器帮助,设置属性值给一个参数对象,然后在初始化的时候设置给post_params.

//这是CSRF那一长串字符
var _token = '<%=form_authenticity_token-%>';
//这是session_id值
var _session_id = '<%=cookie[Rails.application.config.session_options[:key]]-%>';
//这是session的名称,具体设置在config/initializers/session_store.rb里面
var _session_key = '<%-Rails.application.config.session_options[:key]%>';
//设置一个参数对象
var params = {
    'authenticity_token':_token
}
params[_session_key] = _session_id
//如果有别的要提交的参数一一起设置了,然后设置给post_params

  第三步,设置服务器端。

  1.在app下,建立一个middleware文件夹,在里面建立一个中间件的ruby文件,名字随意,我这里叫flash_session_cookie_middleware.rb,事实上网上找来的资料里面都叫这名字,这出自国外一篇文章。代码如下:

require 'rack/utils'

class FlashSessionCookieMiddleware
  def initialize(app, key='_fly84_session')
    @app = app
    @session_key = key
  end

  def call(env)
    if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
      req = Rack::Request.new(env)
      env['HTTP_COOKIE'] = [ @session_key, req.params[@session_key] ].join('=').freeze unless req.params[@session_key].nil?
      #env['HTTP_ACCEPT'] = "#{req.params['_http_accept']}".freeze unless req.params['_http_accept'].nil?
    end
    @app.call(env)
  end
end

  2.加入配置

config/application.rb下,加入

config.autoload_paths += %W( #{Rails.root.to_s}/app/middleware )

config/initializers/session_store.rb中,加入

Rails.application.config.middleware.insert_before(Rails.application.config.session_store, FlashSessionCookieMiddleware, Rails.application.config.session_options[:key])

Rails.application.config.session_options[:key]就是在session_store里面设置的那个session的名字

  好了,就这么多了,设置是挺简单的,原理也很容易理解,就是我自己也不明白,为什么会为了这个弄了N久。第一次弄的时候,连找资料,半小时就好了,然后有点小开心,喝了杯咖啡散了个步,结果再一测试就不行了,然后再找原因再改的,到最后也基本还是这样。但愿接下来顺利。

posted @ 2011-06-24 16:30  灰色逻辑  阅读(900)  评论(0编辑  收藏  举报