在Rails中,会话存储在哪里?

21
在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中声明会话cookie时,我并不清楚浏览器/客户端如何确切地获得访问权限(Rails方面)。

2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
21
你已经接近成功了。不过,我感觉你可能在混淆概念,把苹果和橙子搞混了…… 会话: 通常情况下,在动态网站中,人们希望在HTTP请求之间存储用户数据(因为http是无状态的,否则你不能将一个请求与任何其他请求关联起来),但是你不希望那些数据可以在客户端URL内(比如 yourwebsite.com/yourPage?cookie=12345&id=678)被读取和/或编辑,因为你不想让客户在不经过服务器端代码的情况下操纵这些数据。 解决这个问题的一种方法是将其存储在服务器端,给它一个“会话令牌”(正如你所说的),并且只让客户端知道(并在每个http请求中传回)该令牌。这就是会话的实现方式。 Cookie: Rails中实现会话的最常见技术是使用cookie,它们是放置在用户浏览器上的小段文本。因为cookie从一个页面传递到下一个页面,所以它们可以存储信息(例如会话令牌或其他任何你想要的信息),应用程序可以使用这些信息从数据库中检索已登录的用户。

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安全指南第2节。这可能对您有所帮助。

希望这可以帮助您。


1
会话和Cookie似乎都被存储为Cookie,并且在Chrome上的过期日期是“会话”。即使我关闭浏览器、重新启动计算机等,它们似乎仍然被保留。它们可能是由我的浏览器(Chrome)会话持久化的。我没有找到更多关于这个问题的信息,所以我想知道你在哪里找到一个是临时的,另一个是持久的 - lucasarruda
正确的信息,来自文档并在我的测试中得到确认: 会话和Cookie都存储为Cookie,并且两者都在会话过期时过期。Cookie可以是持久的,但只有在您明确指定时才能如此。例如:cookies [:login] = {value:“XJ-122”,expires:1.week.from_now}将持续一周,而session [:login] =“XJ-122”将持续整个会话(通常在用户退出浏览器时重置)。参考:http://api.rubyonrails.org/v5.1/classes/ActionDispatch/Cookies.html - lucasarruda

1
  • 会话存储在服务器端。
  • Cookie 存储在客户端(浏览器 cookie)。
  • 当客户端/浏览器向 Rails 服务器发送请求时,每次都会发送 Cookie 到 Rails 服务器。

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

  • Rails 将其存储在服务器端。
  • 会话在服务器端保存为键值对(例如 JSON 对象)。

对于每个浏览器,Rails 在 Cookie 中设置一个 会话标识符,以便可以找到请求的正确会话信息。

如果 Cookie 中没有 会话标识符,则 Rails 不知道哪个会话属于哪个浏览器。 因此,没有 Cookie,会话将无法工作。

编辑:解释:会话存储在服务器端

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

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

表单提交到 sessions#login 操作。

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,则不需要在该浏览器中再次设置它,包括第二个、第三个和后续请求。 希望您能理解。

1
谢谢你的回答。问题:会话存储在服务器端 - 你能详细说明一下吗? - BenKoshy
2
@BKSpurgeon 我已经编辑了答案,解释了“会话存储在服务器端”的含义。 - mahfuz
1
这个答案完全是错的。自Rails 4以来,会话并没有被存储在服务器端,因为Rails默认使用cookie存储会话。这种情况至少从Rails 4开始就一直存在了,而混乱的问题与请求之间如何存储会话无关。 - max
@max,请再检查一下。在Rails 7中,当我设置某些会话时,我发现没有添加任何cookie,但我可以在Rails代码中访问此会话。因此,证明会话存储在服务器端。 - mahfuz
1
不,这个答案仍然很荒谬。会话在服务器上反序列化,并在请求期间作为实例变量存在,并随响应一起作为标头发送。但是说它存储在服务器端基本上就像是出于同样的原因存储参数在服务器端一样。毕竟,会话的整个目的是在请求之间传递信息,而这是通过 cookie 完成的。 - max
除非您实际主动安装一个 gem 并重新配置 Rails 使用另一个存储。 - max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,