在 Rails 中存储持久会话数据而不影响正常会话过期

Posted

技术标签:

【中文标题】在 Rails 中存储持久会话数据而不影响正常会话过期【英文标题】:Storing persistent session data in Rails without affecting normal session expiration 【发布时间】:2010-02-14 04:37:13 【问题描述】:

我想为每个浏览器(用户设置)存储一些持久数据,并且不想要求登录才能使用该站点。实现这一目标的最佳方法是什么?

我考虑了两种方法:

    将信息存储在会话 cookie 中。这种方法的问题是我需要在会话 cookie 上设置过期时间,这会导致用户的登录会话在浏览器关闭时不会过期。 将信息存储在数据库中,并将检索密钥存储在客户端的 cookie 中。我担心性能问题,因为这需要额外的查询和可能的反序列化来检索数据。由于性能原因,Rails 似乎不久前从 ActiveRecordStore 切换了默认设置:https://web.archive.org/web/20120102024844/https://www.ryandaigle.com/articles/2007/2/21/what-s-new-in-edge-rails-cookie-based-sessions

推荐的实现方式是什么?

【问题讨论】:

【参考方案1】:

为什么不直接使用非会话 cookie?您可以指定它将在客户端上持续多长时间等。请参阅http://api.rubyonrails.org/classes/ActionController/Cookies.html

如果您担心用户会弄乱 cookie 数据,您可以使用如下技术加密 cookie 数据(取自 http://www.neeraj.name/blog/articles/834-how-cookie-stores-session-data-in-rails):

cookie_data = :foo => "bar"
digest = 'SHA1'
secret = 'my_encryption_secret'
data = ActiveSupport::Base64.encode64s(Marshal.dump(cookie_data))
digest_value = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(digest), secret, data)
escaped_data_value = Rack::Utils.escape(data)
final_output = "#escaped_data_value--#digest_value"
cookies[:user_data] = final_output

稍后读取cookie数据:

Marshal.load(ActiveSupport::Base64.decode64(cookies[:user_data]))

【讨论】:

【参考方案2】:

它实际上是从基于文件的会话存储更改为基于 cookie 的会话存储,而不是从 ActiveRecord。我可能错了,但我相信当基于文件的存储是默认设置时,ActiveRecord 是网络农场或分布式设置的可行选择。自从引入了基于 cookie 的存储后,网络农场场景就不再是问题了,因为它存储在客户端。今天 ActiveRecord 仍然是一个可行的选择,当您想要存储比 cookie 允许的更多的数据时,当您想要减少在每个请求中传输的数据开销(使用 ActiveRecord 意味着您只传输 session_id),或者如果你想要一个集中式会话设置。

我发现在使用 ActiveRecord 会话存储时,速度对我来说不是一个因素。在基于 cookie 的会话中,您通常会限制在会话变量中存储的内容,因此它们往往是用于在数据库中查找数据的标记。如果数据不需要在会话之外持久化,那么将对象存储在会话中而不只是令牌是可行的,因为无论如何您都将访问数据库以获取相关记录。如果您要检索的对象涉及昂贵的检索操作,并且您在会话的生命周期内需要它,则将该对象存储在会话中而不只是令牌中可能是有意义的,并且仅在会话时访问数据库一次是首先建立的。

Cookie 很棒,但请记住,用户可以在需要时删除它们,无论是否加密。随着隐私问题的增加,以及相当多的插件可用于有条件地阻止 cookie 的浏览器以及清理 cookie 的软件,您可能需要权衡使用 cookie 与 db 支持的会话的利弊。

@joshsz 提出了一个很好的观点,即使用非会话 cookie 在会话之外持久化数据。请记住,会话的生命周期是有限的。

【讨论】:

以上是关于在 Rails 中存储持久会话数据而不影响正常会话过期的主要内容,如果未能解决你的问题,请参考以下文章

Rails:如何在会话中存储数据?

在 Rails 的会话中存储对象

在 Rails 应用程序中实现“记住我”

TommEE 会话持久存储不起作用

Ruby on Rails 中的会话如何工作?

如何将数据持久化(转储)到本地存储并在以后的会话中加载?