在 Rails 3 中设置会话超时
Posted
技术标签:
【中文标题】在 Rails 3 中设置会话超时【英文标题】:Setting session timeout in Rails 3 【发布时间】:2011-08-17 04:27:33 【问题描述】:这看起来很简单:我试图让我的 rails Active Record 会话在 2 分钟后超时。因此,两分钟后,我希望我的用户必须重新登录。
我只是在我的本地开发机器上运行 rails server
(即 WebBrick)。
我知道这与config/initalizers/session_store.rb
中的以下代码有关,但我认为我没有完全确定:
CodedOn::Application.config.session_store :active_record_store
CodedOn::Application.configure do
config.action_controller.session = :expire_after => 2.minutes
end
这似乎不起作用,或者至少我的会话似乎没有超时。我找不到太多关于 Rails 3 方法的信息,因为我知道 Rails 2.x 发生了变化。
有人可以帮我吗?
【问题讨论】:
【参考方案1】:我认为您必须手动执行此操作,因为活动记录存储未实现 expire_after 选项。所以在你的(我假设)过滤之前,你应该这样做:
def authenticate
if session[:logged_in]
reset_session if session[:last_seen] < 2.minutes.ago
session[:last_seen] = Time.now
else
... authenticate
session[:last_seen] = Time.now
end
end
显然,这并不完整,但它应该给你基本的想法。
更新:
似乎该功能自 2.3 版起就存在于 rails 中。我找到了相关代码here。这是 AbstractStore,它应该作为所有派生类的基类。因此,正如 dadooda 所建议的那样,以下应该可行:
Some::Application.config.session_store :active_record_store,
expire_after: 24.hours,
【讨论】:
这里的一个问题是它是如何工作的......就像在最初创建会话时调用before_filter
- 即当用户第一次通过身份验证时,session[:last_seen]
是如何工作的又叫了?如果它是一个身份验证 before_filter,它不是只调用一次 - 在身份验证时?我想我想弄清楚的是,一旦创建了会话并且用户登录了,我如何检查session[:last_seen]
,以便如果它超过X
的分钟数,它会迫使他们重新-登录,在会话的初始创建时不这样做。希望这是有道理的
我希望我得到了你的问题:HTTP 是无状态的。因此,网络服务器看不到任何两个请求之间的任何关系。但是有些用例需要这种关系(例如身份验证)。在 Rails 中,会话哈希提供了这一点。但是控制器确实必须读取每个请求的会话哈希,以便识别以前经过身份验证的用户。因此,在每个请求之前都会调用 'authenticate'-before 过滤器。我希望这会有所帮助。
鉴于我是从头开始编写身份验证的,假设我在每个控制器上明确调用 before_filter
,或者我必须在每个控制器上传递 filter_resource_access
,您的答案是否有效?控制器以强制它这样做?我知道如果我使用 devise
或其他一些身份验证 gem,它会为我处理这些东西 - 但鉴于我是从头开始编写的,这就是我问这些问题的原因。
或者rails会在每次控制器请求之前自动调用application_controller中的所有before_filters
?
@marcamillion:这是因为按照惯例,您的控制器都继承自 ApplicationController(例如 class PostsController < ApplicationController
),因此它们继承了 before_filter
声明。【参考方案2】:
我以简单的方式做到了这一点,你可以试试这个:
在你的config/initializers/session_store.rb
中这样做:
Yourapp::Application.config.session_store :cookie_store,
:key => "_yourapp_session",
:expire_after => 2.minutes
这对我很有效,希望对你也有效。
【讨论】:
也适用于 Rails 5.0.0。【参考方案3】:您必须手动完成。下面是为 ActiveRecord 会话创建类方法的示例。您可以使用 Rufus-Scheduler 和/或 DelayedJob 定期调用它。
class Session < ActiveRecord::Base
def self.sweep(time = 1.hour)
if time.is_a?(String)
time = time.split.inject |count, unit| count.to_i.send(unit)
end
delete_all "updated_at < '#time.ago.to_s(:db)' OR created_at < '#2.days.ago.to_s(:db)'"
end
end
更多关于它为何重要的背景信息:http://guides.rubyonrails.org/security.html#session-expiry
【讨论】:
【参考方案4】:mosch 说:
我认为您必须手动执行此操作,因为活动记录存储未实现 expire_after 选项。
似乎不再是这样了。 :expire_after
在 Rails 3.2.11 中为我工作:
Some::Application.config.session_store :active_record_store,
key: "some_session_id",
domain: ".isp.com",
expire_after: 24.hours,
Cookie 会在每次向应用发出请求后自动延长。会话通过浏览器退出持续存在。
我使用上述技巧将跨域的会话“全球化”以实现简单的 SSO 功能,目前看来可行。
【讨论】:
【参考方案5】:到期时间。
MAX_SESSION_TIME = 60 * 60
before_filter :prepare_session
def prepare_session
if !session[:expiry_time].nil? and session[:expiry_time] < Time.now
# Session has expired. Clear the current session.
reset_session
end
# Assign a new expiry time, whether the session has expired or not.
session[:expiry_time] = MAX_SESSION_TIME.seconds.from_now
return true
end
【讨论】:
【参考方案6】:只需在模型中添加 timeout_in 方法,它就可以解决问题:
def timeout_in 2分钟 结尾【讨论】:
以上是关于在 Rails 3 中设置会话超时的主要内容,如果未能解决你的问题,请参考以下文章