【问题标题】: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 存在知识空白。

【问题讨论】:

    标签: ruby-on-rails session cookies


    【解决方案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

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

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

    3. 现在页面重定向到主页。

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

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

    您在仪表板控制器中添加了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
    猜你喜欢
    • 1970-01-01
    • 2016-08-27
    • 2011-02-12
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多