在 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 &lt; 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 中设置会话超时的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ktor 中设置会话超时?

在 Spring MVC 中设置会话超时

如何在 web.config 中设置会话超时

如何在 Laravel 中设置会话超时?

如何在django中设置会话超时?

如何在 ASP.NET Core 的 web.config 中设置会话超时