会话存储在 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 的 session
和 cookies
辅助方法之间有一个重要区别...
它们都生成 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 都会在 cookie 中设置一个session identifier
,这样,Rails 就可以为请求找到正确的会话信息。
如果cookie中没有session identifier
,Rails不知道什么会话属于什么浏览器。
因此,没有 cookie,会话将无法工作。
编辑:说明:会话存储在服务器端
假设,我正在使用您的网络应用程序,登录后我将被重定向到主页。
我打开登录页面,输入用户名和密码,点击登录按钮。
表单提交到sessions#login
action。
在sessions#login
- 你检查username
和password
- 并设置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 中的啥位置?的主要内容,如果未能解决你的问题,请参考以下文章