【问题标题】:In Rails, how do you destroy a session when a browser is closed?在 Rails 中,当浏览器关闭时如何销毁会话?
【发布时间】:2011-07-26 23:00:01
【问题描述】:

我正在阅读 Michael Hartl 的 Railstutorial,但我被困在练习 9.6.2 上。我在网上搜索并在我的 Sessions Helper 中使用了这段代码:

module SessionsHelper

  def sign_in(user)

    session[:user_id] = user.id
    self.current_user = user
  end

  def current_user=(user)
    @current_user = user
  end

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

  def signed_in?
    !current_user.nil?
  end

  def sign_out
    session[:user_id] = nil
    self.current_user = nil
  end
end

我从网上找到的:http://www.nimweb.it/web-development/ruby-on-rails-web-development/ruby-on-rails-tutorial-exercise-9-6-2-rails-session/

但是,当浏览器关闭时,用户并没有注销。还有其他人对此有解决方案吗?

【问题讨论】:

    标签: session railstutorial.org


    【解决方案1】:

    编辑: 查看您提供的链接,他们写道:

    我们还可以启动服务器(使用“$ rails s”)并验证 我们全新会话的运行没有 cookie(我们应该 每次关闭浏览器时都会退出)。

    (强调)

    因此,他们的解决方案是简单地关闭 cookie,这会导致每次访问都会创建一个新会话。他们并不是真的在谈论在等式的服务器端删除旧会话。

    我的原始答案留在下面以获取历史价值:


    (抱歉,如果这太笼统了,我假设您没有看到更大的图景)

    从根本上说,Web 使用基于拉取的模型 - 客户端发出请求以在服务器上执行操作。

    您不能“强制”客户端关闭会话,因为关闭会话是客户端必须从服务器请求的操作(例如:通过注销)。

    因此,会话通常有一个定期检查的超时期限。每个会话都有一个存储在数据库中的“开始时间”,并且太旧的会话将被清除。

    也就是说,javascript 中可能有一些方法可以检测浏览器关闭事件并尽最大努力尝试关闭会话。但不能保证——用户总是可以强行终止浏览器进程,让服务器完全处于黑暗之中。

    简而言之,您不能依赖客户端来关闭会话。超时可能是您最好的选择。

    【讨论】:

    • 值得注意的是,如果没有指定 Expires 选项,cookie 默认会在浏览器关闭时过期(在大多数用户代理中)。
    • 好点 - 虽然只是要明确一点:这不会关闭旧会话(从服务器的角度来看),它只会导致下一次打开一个新会话。跨度>
    【解决方案2】:

    在学习教程时,我被困在同一个练习中。如果您碰巧使用 Firefox 并决定保存选项卡然后退出,那么当您重新启动浏览器时,浏览器显然会保存您的所有会话数据。这意味着保存在会话cookie中的用户信息也将被恢复,因此在浏览器关闭后用户似乎已登录。我不认为其他浏览器(例如chrome)有同样的行为。所以一个快速的测试是使用另一个浏览器,看看你的代码是否可以工作。希望这会有所帮助。

    【讨论】:

    • 我测试了我的 Chrome (ver.20),它会在关闭后保持会话。
    【解决方案3】:

    首先要清除您正在使用的会话存储以避免“混淆”。 我猜这个练习使用 default (cookie) store 但当然你可能已经将其更改为 active record store (或任何其他将数据保存在服务器)。

    检查您的config/initializers/session_store.rb 文件以找出正在使用的会话存储。 假设您没有对存储进行任何更改,则应将其配置为 :cookie_store,在这种情况下,您无需担心任何事情,因为客户端 cookie 用于存储会话数据,并且这些 cookie 默认在浏览器关闭后过期(它们被称为“会话”cookie,为了清楚起见,这里的会话确实是指在您的浏览会话持续存在之前存在的 cookie - 关闭浏览器会删除会话 cookie)。 当然,这不会在浏览器退出时调用任何服务器端代码,例如 sign_out 或 session.destroy,但由于 cookie 包含所有会话数据并被浏览器删除,因此您无法再访问它,因此可能会考虑会话被破坏...

    现在,使用服务器端会话存储,这变得更加复杂,如上一个答案 “您不能'强制'客户端关闭会话”中所述。 大多数人所做的是手动销毁“过期”会话,例如http://guides.rubyonrails.org/security.html#session-expiry。采样 rake 任务https://gist.github.com/kares/919069

    【讨论】:

      【解决方案4】:

      我现在正在阅读这个很棒的教程,并且在大约 30 分钟前完成了同样的任务。 Jeremy Roman 准确回答了这个帖子中的问题。虽然他没有提供一步一步的答案,但他提到的事情让我找到了答案。

      现在更具体地说...考虑到 Jeremy 提到的关于会话在浏览器关闭后自动过期的内容,除非为相应的 cookie 指定了“Expires”属性,否则解决方案是与以下代码块有关:

      app/helpers/session_helper.rb:

      def sign_in(user)
        cookies.permanent.signed[:remember_token] = [user.id, user.salt]
        self.current_user = user
      end
      

      根据tutorial itself,上面的permanent 方法将'Expires' cookie 属性设置为20.years.from_now。因此,这意味着您的会话将持续 20 年,除非您明确注销或删除 cookie。

      因此,为了在浏览器关闭时使会话过期,您只需要创建没有任何过期日期的 cookie,归结为简单地省略 permanent:

      app/helpers/session_helper.rb:

      def sign_in(user)
        cookies.signed[:remember_token] = [user.id, user.salt]
        self.current_user = user
      end
      

      虽然可能还有其他有效的解决方案,但对我来说还不明显(毕竟我刚开始学习 Rails),这个看起来非常简单 - 你甚至不需要写任何东西- 只需删除permanent 即可! :)

      【讨论】:

        【解决方案5】:

        我知道这个答案晚了四年多一点,但我自己也遇到了同样的问题,并且在 SO 上以各种形式多次询问过这个问题。我找到的唯一正确答案是here。

        问题不是问题的设计。当然,这个练习应该在启用 cookie 的情况下完成。相反,问题出在浏览器设置中:启动浏览器时“从上次中断的地方继续”或“打开我上次的窗口和选项卡”。此设置使会话在关闭浏览器时保持活动状态,这正是我们不希望出现的行为。

        这个问题现在在教程中作为脚注引用(第 8 章,注 2)。作者说,关于此浏览器设置及其伴随的永无止境的会话,

        ...Rails 当然无法控制这种行为。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-17
          • 2015-12-13
          • 1970-01-01
          • 1970-01-01
          • 2012-10-21
          相关资源
          最近更新 更多