96

我有一个应用程序设置,其中每个用户都属于一家公司,并且该公司有一个子域(我使用的是 basecamp 风格的子域)。我面临的问题是 Rails 正在创建多个 cookie(一个用于 lvh.me,另一个用于 subdomain.lvh.me),这导致我的应用程序出现了很多中断(例如,尽管所有请求都存在一次,但闪存消息仍然存在)登录)。

我的 /cofig/initilizers/session_store.rb 文件中有这个:

AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all

domain: :all 似乎是我在 Google 上找到的标准答案,但这似乎对我不起作用。任何帮助表示赞赏!

4

9 回答 9

79

事实证明,'domain: all' 为该会话期间访问的所有不同子域创建一个 cookie(并确保它们在请求之间传递)。如果没有传递域参数,则意味着为在同一会话中访问的每个不同域创建一个新的 cookie,而旧的 cookie 将被丢弃。我需要的是一个在整个会话期间保持不变的 cookie,即使在域发生变化时也是如此。因此,通过domain: "lvh.me"解决了开发中的问题。这会创建一个在不同子域之间保留的 cookie。

对于任何需要进一步解释的人,这是一个很好的链接: http ://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

于 2012-05-01T19:46:41.350 回答
70

http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

“这里你要注意的部分是,如果你设置 :domain => :all like 在某些地方是推荐的,除非你使用 localhost,否则它根本不起作用。:all 默认为 TLD 长度 1 ,这意味着如果您使用 Pow (myapp.dev) 进行测试,它也不会工作,因为这是一个长度为 2 的 TLD。”

换句话说,您需要:

 App.config.session_store ... , :domain => :all, :tld_length => 2

清除 cookie 也是一个好主意

于 2013-02-21T18:39:46.517 回答
24

我一直在寻找一种无需明确说明域名即可解决此问题的方法,因此我可以在 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。所以我在 lvh.me 上的 session_store.rb 文件中的子域在开发中以及在生产中的任何其他内容如下。

MyApp::Application.config.session_store :cookie_store, key: '_MyApp_session', domain: :all, tld_length: 2

希望这对某人有所帮助,因为我花了很长时间才找到这个答案!

于 2013-11-12T11:39:04.373 回答
19

由于某种原因:all,用域替换对我来说不起作用(rails 3.2.11)。它需要一个自定义中间件来修复它。该解决方案的摘要如下。

tl;dr:您需要编写一个自定义机架中间件。您需要将其添加到您的conifg/environments/[production|development].rb. 这是在 Rails 3.2.11 上

Cookie 会话通常只为您的顶级域存储。

如果您查看,您会看到and和 andChrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}会有单独的条目sub1.yourdomain.comothersub.yourdomain.comyourdomain.com

挑战是在所有子域中使用相同的会话存储文件。

第 1 步:添加自定义中间件类

这就是Rack Middleware的用武之地。一些相关的 rack & 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 文件。

第 2 步:添加到 Rails 配置

现在您在 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"

请注意,前面的点是必需的。请参阅“子域 cookie,在父域请求中发送? ”了解原因。

然后在你的config/environments/development.rb添加:

config.middleware.use "CustomDomainCookie", ".lvh.me"

lvh.me 技巧映射到 localhost。这很棒。有关更多信息,请参阅此 Railscast 关于子域此说明

希望应该这样做。老实说,我不完全确定为什么这个过程如此复杂,因为我觉得跨子域站点很常见。如果有人对这些步骤背后的原因有任何进一步的见解,请在评论中启发我们。

于 2013-02-06T21:59:14.823 回答
18

我在寻找将 cookie 设置为根域的最简单方法时遇到了这个问题。:all当作为域选项传递时,似乎有一些关于该选项的错误信息。对于大多数域,它实际上会按预期工作,将 cookie 设置为根域(例如.example.comfor test.example.com)。lvh.me我认为大多数人在使用域进行测试时都遇到了问题。rails 用于查找顶级域的正则表达式定义为DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. 如果您注意最后一部分,您可以看到 rails 解释lvh.me为类似于com.au. 如果您的用例需要lvh.me工作,那么该:all选项将无法正常工作,但是,对于大多数域来说,它似乎是最简单和最好的选项。

TL;DR,这里的正确答案,假设您不是在 3 个字母的域(或任何混淆上述正则表达式的域)上开发,则使用:all.

于 2013-07-16T01:43:16.247 回答
8

Rails 4.x(也应该适用于 Rails 5/6 版本)

如何在 localhost (Rails) 中获取 lvh.me:3000 和子域

开发:我已共享 cookie 以添加.lvh.mesession_store.rb,

它将在 localhost 上的子域之间共享admin.lvh.me:3000lvh.me:3000依此类推...

#config/initializers/session_store.rb

domain = Rails.env.production? ? ".domain_name.com" : ".lvh.me"

Rails.application.config.session_store :cookie_store, 
                      key: '_app_name_session', domain: domain
于 2017-03-26T01:12:02.727 回答
4

你试过了吗

AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'  

)

基本上我们说的是基域有单个 cookie,只是忽略子域..虽然这种方法仍然有一些缺陷......

于 2012-05-01T19:51:47.517 回答
2

支撑导轨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

于 2018-10-18T03:18:21.240 回答
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 
于 2020-06-25T04:39:32.510 回答