Ruby on rails 在Rails中的子域之间共享会话(cookies)?
我有一个应用程序设置,每个用户都属于一家公司,该公司有一个子域(我使用的是basecamp风格的子域)。我所面临的问题是rails正在创建多个cookie(一个用于lvh.me,另一个用于subdomain.lvh.me),这在我的应用程序中造成了相当多的中断(例如,flash消息在登录后会持久化,尽管所有请求都会断开) 在我的/cofig/initilizers/session\u store.rb文件中有:Ruby on rails 在Rails中的子域之间共享会话(cookies)?,ruby-on-rails,session,devise,Ruby On Rails,Session,Devise,我有一个应用程序设置,每个用户都属于一家公司,该公司有一个子域(我使用的是basecamp风格的子域)。我所面临的问题是rails正在创建多个cookie(一个用于lvh.me,另一个用于subdomain.lvh.me),这在我的应用程序中造成了相当多的中断(例如,flash消息在登录后会持久化,尽管所有请求都会断开) 在我的/cofig/initilizers/session\u store.rb文件中有: AppName::Application.config.session_store
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all
域名::all似乎是我在谷歌上找到的标准答案,但这似乎对我不起作用。感谢您的帮助 事实证明,“domain:all”为会话期间访问的所有不同子域创建一个cookie(并确保它们在请求之间传递)。如果未传递任何域参数,则意味着将为同一会话中访问的每个不同域创建一个新cookie,而旧cookie将被丢弃。我需要的是一个在整个会话过程中保持不变的cookie,即使域发生了变化。因此,通过
域:“lvh.me”
解决了开发中的问题。这会在不同的子域之间创建一个cookie
对于任何需要进一步解释的人,这是一个很好的链接:
你试过了吗
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'
)
基本上,我们说的是基本域只有一个cookie,而忽略子域。尽管这种方法仍然有一些缺陷 出于某种原因,用域替换
:所有对我来说都不起作用(rails 3.2.11)。需要一个定制中间件来修复它。该解决方案的摘要如下
tl;dr:您需要编写一个自定义机架中间件。您需要将其添加到您的conifg/environments/[production | development].rb
中。这是在Rails 3.2.11上
Cookie会话通常仅为顶级域存储
如果您查看Chrome->Settings->Show advanced Settings…->隐私/内容设置…->所有cookie和站点数据…->搜索{yourdomain.com}
,您可以看到sub1.yourdomain.com
和othersub.yourdomain.com
将有单独的条目
挑战在于跨所有子域使用相同的会话存储文件
步骤1:添加自定义中间件类
这就是我们的优势所在。一些相关机架和导轨资源:
- 和的机架文档
下面是一个自定义类,您应该将其添加到lib
这是他写的,你们都应该感谢他
# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
def initialize(app, default_domain)
@app = app
@default_domain = default_domain
end
def call(env)
host = env["HTTP_HOST"].split(':').first
env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{@default_domain}"
@app.call(env)
end
def custom_domain?(host)
host !~ /#{@default_domain.sub(/^\./, '')}/i
end
end
基本上,它会将所有cookie会话数据映射回与根域相同的cookie文件
步骤2:添加到Rails配置
现在您在lib中有了一个自定义类,请确保您正在自动加载它。如果这对你来说毫无意义,请看这里:
第一件事是确保您在系统范围内使用cookie存储。在config/application.rb
中,我们告诉Rails使用cookie存储
# We use a cookie_store for session data
config.session_store :cookie_store,
:key => '_yourappsession',
:domain => :all
这里之所以提到这一点,是因为:domain=>:all
行。还有其他人建议指定:domain=>”.yourdomain.com“
,而不是:domain=>:all
。出于某种原因,这对我不起作用,我需要如上所述的自定义中间件类
然后在您的配置/environments/production.rb中添加:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
config.middleware.use "CustomDomainCookie", ".lvh.me"
请注意,前面的点是必要的。请参阅“”了解原因
然后在您的配置/environments/development.rb中添加:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
config.middleware.use "CustomDomainCookie", ".lvh.me"
lvh.me技巧映射到localhost。太棒了。有关更多信息,请参阅和
希望这样就可以了。老实说,我不完全确定为什么这个过程如此复杂,因为我觉得跨子域站点很常见。如果有人对这些步骤背后的原因有任何进一步的见解,请在评论中告诉我们。
“您需要注意的是,如果您设置:domain=>
当前位置在某些地方建议使用all like,除非
您使用的是localhost.:all默认为TLD长度1,即
这意味着如果您使用Pow(myapp.dev)进行测试,它也不会工作
因为这是长度为2的TLD。”
换句话说,您需要:
App.config.session_store ... , :domain => :all, :tld_length => 2
清除cookie也是一个好主意我在寻找将cookie设置为根域的最简单方法时遇到了这个问题。当作为域选项传递时,:all
选项似乎有一些错误信息。对于大多数域,它实际上会按预期工作,将cookie设置为根域(例如test.example.com
,对于test.example.com
)。我认为大多数人在使用域lvh.me
进行测试时都会遇到问题。rails用于查找顶级域的正则表达式被定义为domain\u REGEXP=/[^.]*\.([^.]*.\\.\\.\\.\\\.\\.\\\.\\.\\\.$/
。如果注意最后一部分,您可以看到rails将lvh.me
解释为类似于com.au
的TLD。如果您的用例需要lvh.me
才能工作,那么:all
选项将无法正常工作,然而,对于大多数域来说,它似乎是最简单和最好的选项
TL;DR,这里的正确答案是,假设您不是在一个3个字母的域(或任何混淆上述正则表达式的域)上开发,那么使用:all
我正在寻找一种方法来解决这个问题,而不必显式声明域名,这样我就可以在localhost、lvh.me和,以及我将在生产中使用的任何域,而无需继续编辑session_store.rb文件。然而,设置“domain::all”似乎并不适合我
最终我发现我需要声明tld_长度(顶级域长度)
Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: :all, tld_length: 2
Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: {
production: '.example.com',
development: '.example.dev'
}.fetch(Rails.env.to_sym, :all)
if Rails.env.development?
Rails.application.config.session_store :redis_store, {
servers: [
{ host: 'localhost', port: 6379},
],
key: '_app_session',
expire_after: 1.day,
domain: :all
}
else
Rails.application.config.session_store :redis_store, {
servers: [
{ host: HOST_URL, port: PORT},
],
key: '_app_session',
expire_after: 1.day,
domain: '.domain.com',
tld_length: 2
}
end