会话存储在 Rails 中的啥位置?

Posted

技术标签:

【中文标题】会话存储在 Rails 中的啥位置?【英文标题】:Where is the Session Stored in Rails?会话存储在 Rails 中的什么位置? 【发布时间】:2015-10-01 04:05:43 【问题描述】:

在 Rails 中,我为用户身份验证实现了以下代码(确认是正确的)。但是,我想确认我对这个奇怪的session[:session_token] 的想法。这是存储在浏览器中的“cookie”吗?

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  helper_method :current_user, :signed_in?

  private
  def current_user
    @current_user ||= User.find_by_session_token(session[:session_token])
  end

  def signed_in?
    !!current_user
  end

  def sign_in(user)
    @current_user = user
    session[:session_token] = user.reset_token!
  end

  def sign_out
    current_user.try(:reset_token!)
    session[:session_token] = nil
  end

  def require_signed_in!
    redirect_to new_session_url unless signed_in?
  end
end 

到目前为止,我对其工作原理的理解是,每当浏览器/客户端向 rails 发送请求时,cookie(带有session[:session_token])也会被发送过来,从而允许current_user 方法找到用户。我的理解正确吗?这对我来说很奇怪,因为当我们在 ApplicationController(Rails 端)中声明它时,浏览器/客户端如何访问会话 cookie 存在知识空白。

【问题讨论】:

【参考方案1】:

你几乎在那里。虽然,我感觉你可能把苹果和橙子混为一谈了……

会话:

通常在动态网站中,人们希望在 HTTP 请求之间存储用户数据(因为 http 是无状态的,并且您不能以其他方式将请求与任何其他请求相关联),但您不希望该数据可读和/或在 URL 内部的客户端上可编辑(例如.. yourwebsite.com/yourPage?cookie=12345&id=678),等等...,因为您不希望客户端玩弄那个数据无需通过您的服务器端代码。

解决此问题的一种方法是将数据存储在服务器端,给它一个“session_token”(正如您所说的那样),并让客户端只知道(并在每个 http 请求时传回)该令牌。这就是会话的实现方式。

Cookie:

在 Rails 中实现会话的最常用技术涉及使用 cookie,它们是放置在用户浏览器上的小段文本。因为 cookie 从一页持续到下一页,所以它们可以存储信息(例如 session_token 或您想要的任何其他信息),应用程序可以使用这些信息从数据库中检索登录用户。

Session 在 Rails 中存储在哪里?

使用上述两个概念,我现在可以告诉您,Rails 中的默认会话存储是CookieStore,大小约为 4KB。

简单地说……

def sign_in(user)
  @current_user = user
  session[:session_token] = user.reset_token!
end

...您定义的方法将用户置于临时会话中。

那么想法就是下面...

def current_user
  @current_user ||= User.find_by_session_token(session[:session_token])
end

...方法将从数据库中找到并检索与会话令牌对应的用户,并将其初始化为您指定的变量。

附加信息:

您还应该注意,Rails 的 sessioncookies 辅助方法之间有一个重要区别...

它们都生成 cookie,但是,session[...] 方法生成 临时 cookie,它应该在浏览器退出时过期,而 cookies[...] 方法创建 持久 cookie,它不要。

此外,我建议您查看Ruby on Rails Security guide 的第 2 节。您可能会发现它很有用。

希望对你有所帮助。

【讨论】:

会话和 cookie 似乎都存储为 cookie,Chrome 上的过期日期为 Session。即使我关闭浏览器、重新启动计算机等,它们似乎都仍然存在。它们可能由我的浏览器(Chrome)会话持续存在。我没有找到更多这方面的信息,所以我想知道你在哪里找到一个是临时而另一个是持久 来自文档并在我的测试中确认的正确信息:会话和 cookie 都存储为 cookie,并且会话到期时都会到期。 Cookie 可以是持久的,但前提是您明确表示。示例:cookies[:login] = value: "XJ-122", expires: 1.week.from_now 将持续一周,而session[:login] = "XJ-122" 将持续到会话持续(通常在用户退出浏览器时重置)。参考:api.rubyonrails.org/v5.1/classes/ActionDispatch/Cookies.html【参考方案2】: 会话存储在服务器端。而且, Cookie 存储在客户端(在浏览器 cookie 中)。而且, 当客户端/浏览器向 Rails 服务器发送请求时,每次将 cookie 发送到 Rails 服务器。

在 Rails 服务器中设置会话时,如:session[:user_id] = 4

Rails 将其存储在服务器端。 Session 像键值对(像 json 对象)一样保存在服务器端

对于每个浏览器,Rails 都会在 cookie 中设置一个session identifier,这样,Rails 就可以为请求找到正确的会话信息。

如果cookie中没有session identifier,Rails不知道什么会话属于什么浏览器。 因此,没有 cookie,会话将无法工作。

编辑:说明:会话存储在服务器端

假设,我正在使用您的网络应用程序,登录后我将被重定向到主页。

我打开登录页面,输入用户名和密码,点击登录按钮。

表单提交到sessions#login action。

sessions#login - 你检查usernamepassword - 并设置session[:session_token]

if username and password is correct
  random_unique_identifier_string = @user.remember_token
  session[:session_token] = random_unique_identifier_string
  redirect_to root_url
end

当服务器运行此代码session[:session_token] 时,服务器需要每个浏览器会话的唯一标识符。

所以,服务器为此浏览器生成一个唯一标识符,例如:abc123

    服务器将所有会话变量设置在一个地方(可能在某个文件夹或数据库中),将此文件夹标记为abc123

    现在服务器向浏览器发送 cookie 请求 - 设置 cookie _ebook_session = abc123。 (我明白了,如果我的应用名称是ebook,那么在rails 中,cookie 名称就像:_ebook_session

    现在页面重定向到主页。

** 注意:以上所有内容都发生在单个请求中**

现在,在我的浏览器中,我想打开一些需要身份验证的页面(假设是仪表板页面)。

您在仪表板控制器中添加了before_action: require_signed_in!

所以,当我在浏览器中打开 dashboard 页面时,浏览器默认情况下会随每个请求发送所有 cookie。所以_ebook_session cookie 被发送到服务器。您的服务器获取_ebook_session cookie 的值是abc123。现在您的应用程序知道我们需要在abc123 文件夹中查找会话。现在您可以从abc123 文件夹中获取session[:session_token] 的值。

** 我已经解释了上面的第二个请求**

每个浏览器都需要唯一的会话标识符。

重要提示:_ebook_session cookie 将在第一次请求时在浏览器中设置。如果我们已经在浏览器中设置了_ebook_session cookie,我们不需要在该特定浏览器中再次设置它,第二个,第三个和下一个请求。

希望你明白。

【讨论】:

感谢您的回答。问:会话存储在服务器端 - 你能详细说明一下吗? @BKSpureon 我已经编辑了答案来解释sessions are stored server side

以上是关于会话存储在 Rails 中的啥位置?的主要内容,如果未能解决你的问题,请参考以下文章

将用户信息放在会话中的啥位置

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

在 Rails 的会话中存储对象

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

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

Rails ActiveRecord 会话存储在 HTML5 SessionStorage 中而不是 Cookie