我有一个应用程序设置,其中每个用户都属于一个公司,并且该公司有一个子域(我使用的是basecamp样式的子域)。我面临的问题是rails正在创建多个cookie(一个用于lvh.me,另一个用于subdomain.lvh.me),这在我的应用程序中造成了相当多的中断(例如flash消息在所有请求中都是持久的签到)。
我在/cofig/initilizers/session_store.rb文件中有这个:
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all
域名:所有似乎都是我在谷歌上找到的标准答案,但这似乎对我不起作用。任何帮助表示赞赏!
答案 0 :(得分:67)
当它变为'domain:all'时,会为该会话期间访问的所有不同子域创建一个cookie(并确保它们在请求之间传递)。如果没有传递域参数,则意味着为在同一会话中访问的每个不同域创建新cookie,旧的cookie被丢弃。我需要的是一个在整个会话期间持久存在的cookie,即使域名发生变化也是如此。因此,通过domain: "lvh.me"
解决了开发中的问题。这会创建一个位于不同子域之间的cookie。
对于需要进一步解释的人来说,这是一个很好的链接: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
答案 1 :(得分:59)
http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
“您要注意的部分是,如果您设置:domain => :所有人都喜欢在某些地方推荐,除非是这样,否则就行不通 你正在使用localhost。 :所有默认值都是TLD长度为1 意味着如果您使用Pow(myapp.dev)进行测试,它也无法正常工作 因为这是一个长度为2的TLD。“
换句话说,你需要:
App.config.session_store ... , :domain => :all, :tld_length => 2
清除Cookie也是一个好主意
答案 2 :(得分:21)
我一直在寻找一种方法来解决这个问题,而不必明确说明域名,所以我可以在localhost,lvh.me和我在生产中使用的任何域之间跳转,而不必继续编辑session_store.rb文件。但是,设置“domain :: all”似乎对我没用。
最终我发现我需要在该表达式中声明tld_length(顶级域长度)。默认tld_length为1,而example.lvh.me的tld_length为2,而127.0.0.1.xip.io的tld_length为5。那么我在session.store.rb文件中的lvh.me中的子域名以及生产中的其他内容如下所示。
MyApp::Application.config.session_store :cookie_store, key: '_MyApp_session', domain: :all, tld_length: 2
希望这有助于某人,因为我花了很长时间才找到这个答案!
答案 3 :(得分:16)
由于某些原因,用域名替换:all
对我来说不起作用(rails 3.2.11)。它花了一块自定义中间件来修复它。该解决方案的摘要如下。
tl; dr:您需要编写自定义的Rack Middleware。您需要将其添加到conifg/environments/[production|development].rb
。这是在Rails 3.2.11
Cookie会话通常仅存储在您的顶级域名中。
如果您查看Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}
您可以看到sub1.yourdomain.com
和othersub.yourdomain.com
以及yourdomain.com
面临的挑战是在所有子域中使用相同的会话存储文件。
这就是Rack Middleware的用武之地。一些相关的机架& rails资源:
以下是您应在lib
中添加的自定义类
这是由@Nader撰写的,你们都应该感谢他
# 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文件。
既然您在lib中有自定义类,请确保自动加载它。如果这对您没有任何意义,请查看此处:Rails 3 autoload
首先要确保您使用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
。出于某种原因,这对我不起作用,我需要如上所述的自定义中间件类。
然后在 config/environments/production.rb
中添加:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
请注意前面的点是必要的。有关原因,请参阅“sub-domain cookies, sent in a parent domain request?”。
然后在 config/environments/development.rb
中添加:
config.middleware.use "CustomDomainCookie", ".lvh.me"
lvh.me技巧映射到localhost。这很棒。有关详细信息,请参阅this Railscast about subdomains和this note。
希望应该这样做。老实说,我不完全确定为什么这个过程很复杂,因为我觉得跨域子站点很常见。如果有人对这些步骤背后的原因有任何进一步的见解,请在评论中启发我们。
答案 4 :(得分:16)
我在寻找将cookie设置为根域的最简单方法时遇到了这个问题。当作为域选项传递时,似乎有关于:all
选项的一些错误信息。对于大多数域,它实际上将按预期工作,将cookie设置为根域(例如.example.com
为test.example.com
)。我认为大多数人都会遇到问题,因为他们正在使用域lvh.me
进行测试。 rails用于查找顶级域的正则表达式被定义为DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
。如果您注意到最后一部分,则可以看到rails将lvh.me
解释为类似于com.au
的顶级域名。如果您的用例需要lvh.me
才能生效,那么:all
选项将无法正常运行,但对于大多数域而言,它似乎是最简单和最佳的选项。
TL; DR,这里的正确答案,假设您不是在3字母域(或任何混淆上述正则表达式的域)上开发,则使用:all
。
答案 5 :(得分:4)
Rails 4.x (对于Rails 5版本也应该没问题)
How to get lvh.me:3000 and subdomain in localhost (Rails)
简单地说,我已共享Cookie以将.lvh.me
添加到session_store.rb
,
它将在localhost admin.lvh.me:3000
,lvh.me:3000
上的子域名之间共享,等等......
#config/initializers/session_store.rb
if Rails.env.production?
Rails.application.config.session_store :cookie_store,
key: '_app_name_session', domain: ".domain_name.com"
else
Rails.application.config.session_store :cookie_store,
key: '_app_name_session', domain: '.lvh.me'
end
答案 6 :(得分:3)
你试过吗
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'
)
基本上我们说基础域有单个cookie而只是忽略子域。虽然这种方法仍有一些缺陷......
答案 7 :(得分:0)
支撑轨5
如果您希望它适用于任何域:
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)
参考:https://github.com/plataformatec/devise/wiki/How-To:-Use-subdomains
答案 8 :(得分:0)
如果您将Redis用于会话存储。
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