在 Rails 中的子域之间共享会话(cookie)?
Posted
技术标签:
【中文标题】在 Rails 中的子域之间共享会话(cookie)?【英文标题】:Share session (cookies) between subdomains in Rails? 【发布时间】:2012-05-11 06:42:51 【问题描述】:我有一个应用设置,其中每个用户都属于一家公司,并且该公司有一个子域(我使用的是 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
The domain: :all 似乎是我在 Google 上找到的标准答案,但这似乎对我不起作用。任何帮助表示赞赏!
【问题讨论】:
【参考方案1】:如果您使用 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
【讨论】:
【参考方案2】:Rails 4.x(也应该适用于 Rails 5/6 版本)
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
domain = Rails.env.production? ? ".domain_name.com" : ".lvh.me"
Rails.application.config.session_store :cookie_store,
key: '_app_name_session', domain: domain
【讨论】:
【参考方案3】:事实证明,'domain: all' 会为该会话期间访问的所有不同子域创建一个 cookie(并确保它们在请求之间传递)。如果没有传递域参数,则意味着为在同一会话中访问的每个不同域创建一个新的 cookie,而旧的 cookie 将被丢弃。我需要的是一个在整个会话期间保持不变的 cookie,即使在域发生变化时也是如此。因此,通过domain: "lvh.me"
解决了开发中的问题。这会创建一个 cookie,并在不同的子域之间保留。
对于任何需要进一步解释的人,这是一个很好的链接: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
【讨论】:
谢谢老兄..我的一个项目一直面临这个问题..终于找到了解决方案.. 确保在所有应用程序中使用相同的config.secret_key_base
,否则将无法解码 cookie。
我没有看到任何与 Rails 4 相关的问题。你知道这是否已经改变。我无法让它与我的项目一起使用。它不断地重新创建 cookie。谢谢。
如果我想使用CacheStore
将会话存储在memcached 中怎么办?
使用 Rails4,我发现这仅适用于带有破折号但不带有下划线的子域:Appname::Application.config.session_store :cookie_store, key: '_appname_session', domain: :all, tld_length: 2
【参考方案4】:
支持rails5
如果您希望它适用于任何域:
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
【讨论】:
【参考方案5】:我正在寻找一种无需明确说明域名即可解决此问题的方法,因此我可以在 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
希望这对某人有所帮助,因为我花了很长时间才找到这个答案!
【讨论】:
【参考方案6】:我在寻找将 cookie 设置为根域的最简单方法时遇到了这个问题。当作为域选项传递时,似乎有一些关于 :all
选项的错误信息。对于大多数域,它实际上会按预期工作,将 cookie 设置为根域(例如,.example.com
用于 test.example.com
)。我认为大多数人都遇到了问题,因为他们使用域lvh.me
进行测试。 rails 用于查找***域的正则表达式定义为DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
。如果您注意最后一部分,您可以看到 rails 将lvh.me
解释为类似于com.au
的TLD。如果您的用例需要lvh.me
才能工作,那么:all
选项将无法正常工作,但是对于大多数域来说,它似乎是最简单和最好的选项。
TL;DR,这里的正确答案,假设您不是在 3 个字母的域(或任何混淆上述正则表达式的域)上开发,则使用 :all
。
【讨论】:
谢谢,这终于帮助我理解了为什么这么多答案都推荐 tld_length 为 2,但为什么我不需要! 这个答案需要更高。谢谢,先生。 “lvh.me 作为一个类似于 com.au 的***域名”顺便说一句,Rails 确实应该以同样的方式解释 .me,因为它也是一个国家域(黑山)。【参考方案7】:http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
“这里你要注意的部分是,如果你设置 :domain => :all like 在某些地方是推荐的,它根本行不通,除非 你正在使用本地主机。 :all 默认为 TLD 长度为 1,即 意味着如果您使用 Pow (myapp.dev) 进行测试,它也不会工作 因为那是一个长度为 2 的 TLD。”
换句话说,你需要:
App.config.session_store ... , :domain => :all, :tld_length => 2
清除 cookie 也是一个好主意
【讨论】:
这是最好的答案,因为一个更改适用于所有环境(app.com 和 app.dev)。不需要自定义中间件。清除 cookie 也很好! 你错过了, :tld_length => 2
确保在所有应用程序中使用相同的config.secret_key_base
,否则将无法解码 cookie。
:domain => :all
在 Rails 4 中不起作用,试试domain => 'lvh.me', tld_length = 2
。它对我有用
在 Rails 4.2 中,我在使用 domain: :all, tld_length: 2
域时得到了很好的结果。【参考方案8】:
由于某种原因,用域替换 :all
对我来说不起作用(rails 3.2.11)。它需要一个自定义中间件来修复它。该解决方案的摘要如下。
tl;dr: 您需要编写一个自定义的机架中间件。您需要将其添加到您的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
会有单独的条目
挑战是在所有子域中使用相同的会话存储文件。
第 1 步:添加自定义中间件类
这就是Rack Middleware 的用武之地。一些相关的机架和导轨资源:
Railscasts about Rack Railsguide for Rack sesssions abstractly 和cookie sessions 的机架文档这是一个自定义类,您应该将其添加到 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"
请注意,前面的点是必需的。请参阅“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 了解更多信息。
希望应该这样做。老实说,我不完全确定为什么这个过程如此复杂,因为我觉得跨子域站点很常见。如果有人对这些步骤背后的原因有任何进一步的见解,请在 cmets 中赐教。
【讨论】:
有没有办法让它与多个***域一起工作?我有一个在不同国家运行的产品。在这里,我们假设默认域是 yourdomain.com,但如果它应该适用于 .be .sv .fr .com.br .com.ar 等呢?谢谢。 我无法让它工作。我正在 Rails 4 中开发,似乎 rias 只是轻轻地忽略了上面的所有代码。它只是不想跨子域共享会话。 @OleHenrikSkogstrøm 确保在所有应用程序中使用相同的config.secret_key_base
,否则将无法解码 cookie。【参考方案9】:
你试过了吗
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'
)
基本上我们说的是基域只有一个 cookie,只是忽略子域..虽然这种方法仍然存在一些缺陷......
【讨论】:
以上是关于在 Rails 中的子域之间共享会话(cookie)?的主要内容,如果未能解决你的问题,请参考以下文章