Rack:单个Rack应用程序的多个会话cookie

4
如何在单个Rack应用程序中与多个会话Cookie(针对不同路径或域)进行交互?例如,考虑使用3个位置的以下应用程序:
- www.my-app.net => 主要应用程序 - www.my-app.net/app_a => 子应用程序A - app_b.my_app.net/ => 子应用程序B
应该能够与3个会话Cookie进行交互:
- domain=www.my-app.net;path=/; - domain=www.my-app.net;path=/app_a; - domain=app_b.my-app.net/;path=/;
Rack :: Session :: Cookie似乎是一个很好的选择,但作为中间件,会话Cookie必须在config.ru中设置,并且似乎被限制为每个Rack应用程序一个会话Cookie。
在这种特殊情况下,主Rack应用程序的重点在于轻松添加子应用程序,因此将应用程序分成多个Rack应用程序以使用Rack :: Session :: Cookie不是可行的解决方案。
理想情况下,应该有一种从Rack应用程序代码内自由交互多个会话Cookie的方法。
现在,我正在考虑:
- 编写一个中间件,允许与多个会话Cookie进行交互 - 使用CGI :: Cookie实现自定义会话Cookie管理应用内部
但两者都相当繁琐,因此我想知道是否有更简单的方法实现此功能。
感谢您提供的任何建议或建议。
1个回答

3
如果有人有同样的需求,我发现创建一个用于管理应用程序内部会话的类是最简单的方法。
Rack::Utils有两个很好的快捷方式:Rack::Utils.set_cookie_header!Utils.delete_cookie_header!可以在处理cookie时真正地简化事情。
我正在将会话保存在使用我的应用程序的数据库中,但支持另一个后端应该是微不足道的。
顺便说一下,我想到了一些考虑因素:
- 为确保cookie名称有效,我正在使用子应用程序名称的sha-1。 - SecureRandom.urlsafe_base64可用于生成会话密钥。 - 必须手动实现会话清理和刷新。

示例代码

管理cookie的类,commit函数将cookie设置和删除到rack中。
class Framework::Response::Cookies

  def set( params )
    @cookies[params.delete( :name )] = params
  end

  def remove( params )
    @remove_cookies[params.delete( :name )] = params
  end

  def commit( headers )
    @cookies.each_pair do |name, params|
      Rack::Utils.set_cookie_header!( headers, name, params )
    end
    @remove_cookies.each_pair do |name, params|
      Rack::Utils.delete_cookie_header!( headers, name, params )
    end
  end

end

管理会话的类(使用Mongo作为后端):
class Database::Mongo::Session < Session

  def save
    expire = Time.now + @session_ttl
    @framework.content.db.find_and_modify( self.collection_name, { 
      :query => { :name => @session_name, :id => @session_id }, 
      :update => { :expire => expire, :name => @session_name, :id => @new_session_id || @session_id , :variables => @variables.to_hash },
      :upsert => true 
    })
    @framework.response.cookies.set( 
      :name => @session_name,
      :value => @new_session_id || @session_id,
      :path => @framework.applications.active.active_request['path'],
      :domain => @framework.applications.active.active_request['host'],
      :httponly => true  
    )
  end

  def delete
    @framework.content.db.remove( self.collection_name, { :id => @session_id } )
    @framework.response.cookies.remove( :name => @session_name )
  end

end

每次调用@framework.response.cookies.set,都会向Framework::Response::Cookies类的@cookies变量中添加一个cookie数据。
在响应被发送之前,调用Framework::Response::Cookies.commit通过Rack::Utils提交cookie。

你能详细介绍一下如何在单个 Rack 应用程序中管理多个 cookie 吗?如果我调用 use Rack::Session::Cookie,我会得到一个当前会话的 cookie。但似乎再次调用它会用新的 cookie 覆盖旧的 cookie(我无法再访问旧的 cookie)?我应该创建多个类并在每个类中调用"use"来获得不同的 cookies吗?欢迎所有输入/代码示例! - Steve Midgley
1
@SteveMidgley 我添加了一些示例代码,这些代码可能有点陈旧,因此也许有更好的方法可以使用较新版本的rack来完成。希望它能有所帮助。 - Eric
谢谢@Eric - 我想我通过调用response.set_cookie(key, string)解决了我的问题 - 这将基于启用cookie时设置的cookie配置参数添加一个新的cookie键值对集合。再次感谢您的跟进! - Steve Midgley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接