在Rails中,如何在浏览器关闭时销毁会话?

时间:2011-07-26 23:00:02

标签: session railstutorial.org

我正在阅读迈克尔·哈特尔的“轨道教程”,并且我坚持练习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/

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

5 个答案:

答案 0 :(得分:4)

修改: 看看你给出的链接,他们写道:

  

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

(强调补充)

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

我的原始答案留下了历史价值:


(道歉,如果这太笼统,我假设你没有看到更大的图片)

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

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

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

也就是说,javascript中可能有某种方法来检测浏览器关闭事件并尽一切努力关闭会话。但是无法保证 - 用户总是可以强行终止浏览器进程,让服务器完全处于黑暗状态。

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

首先要清除你正在使用哪个会话商店以避免“混淆”。 我想这个练习使用了默认(cookie)商店,但当然你可能已经将它改为活动记录存储(或任何其他保存数据的商店)服务器)。

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

现在,使用服务器端会话存储会变得更加复杂,如上一个答案中所提到的“你不能强迫”客户端关闭会话“。 大多数人所做的是手动破坏“过期”会话,例如http://guides.rubyonrails.org/security.html#session-expiry。示例佣金任务https://gist.github.com/kares/919069

答案 3 :(得分:0)

我现在正在阅读这篇精彩的教程,并在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方法将“过期”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即可! :)

答案 4 :(得分:0)

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

问题不在于问题的设计。当然,预计这项练习将在启用cookie的情况下完成。相反,问题出在浏览器设置中:在启动浏览器时“从上次停止的地方继续”或“从上次打开我的窗口和标签”。此设置使会话在浏览器关闭时保持活动状态,这正是我们不想要的行为。

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

  

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