Ruby-on-rails 在 Rails 的子域之间共享会话(cookie)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10402777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Share session (cookies) between subdomains in Rails?
提问by Wahaj Ali
I have an app setup where each user belongs to a company, and that company has a subdomain (I am using basecamp style subdomains). The problem that I am facing is that rails is creating multiple cookies (one for lvh.me and another for subdomain.lvh.me) which is causing quite a few breaks in my application(such as flash messages being persistent though out all requests once signed in).
我有一个应用程序设置,其中每个用户都属于一个公司,并且该公司有一个子域(我使用的是 basecamp 样式子域)。我面临的问题是,rails 正在创建多个 cookie(一个用于 lvh.me,另一个用于 subdomain.lvh.me),这导致我的应用程序出现了很多中断(例如,尽管所有请求一次,闪存消息仍然存在)已登录)。
I have this in my /cofig/initilizers/session_store.rb file:
我的 /cofig/initilizers/session_store.rb 文件中有这个:
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all
The domain: :all seems to be the standard answer I found on Google, but that doesn't seem to be working for me. Any help is appreciated!
domain::all 似乎是我在 Google 上找到的标准答案,但这似乎对我不起作用。任何帮助表示赞赏!
采纳答案by Wahaj Ali
As it turns outs 'domain: all' creates a cookie for all the different subdomains that are visited during that session (and it ensures that they are passed around between request). If no domain argument is passed, it means that a new cookie is created for every different domain that is visited in the same session and the old one gets discarded. What I needed was a single cookie that is persistent throughout the session, even when the domain changes. Hence, passing domain: "lvh.me"solved the problem in development. This creates a single cookie that stays there between different subdomains.
事实证明,“域:全部”为该会话期间访问的所有不同子域创建了一个 cookie(并确保它们在请求之间传递)。如果没有传递域参数,则意味着为同一会话中访问的每个不同域创建一个新 cookie,旧的将被丢弃。我需要的是一个在整个会话中持续存在的 cookie,即使域发生变化。因此,传递domain: "lvh.me"解决了开发中的问题。这将创建一个单独的 cookie,该 cookie 保留在不同的子域之间。
For anyone needing further explanation, this is a great link: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
对于任何需要进一步解释的人,这是一个很好的链接:http: //excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
回答by montrealmike
http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/
"The part you want to watch out for here is that if you set :domain => :all like is recommend in some places, it simply won't work unless you're using localhost. :all defaults to a TLD length of 1, which means if you're testing with Pow (myapp.dev) it won't work either because that is a TLD of length 2."
“您要注意的部分是,如果您设置 :domain => :all like 是在某些地方推荐的,除非您使用 localhost,否则它根本无法工作。:all 默认为 1 的 TLD 长度,这意味着如果你使用 Pow (myapp.dev) 进行测试,它也不会工作,因为这是一个长度为 2 的 TLD。”
In other words you need:
换句话说,您需要:
App.config.session_store ... , :domain => :all, :tld_length => 2
Also a good idea to clear your cookies
清除 cookie 也是一个好主意
回答by FangedParakeet
I was looking for a way to solve this problem without having to explicitly state the domain name, so I could hop between localhost, lvh.me, and whichever domains I would use in production without having to keep editing the session_store.rb file. However, setting "domain: :all" didn't seem to be working for me.
我正在寻找一种无需明确说明域名即可解决此问题的方法,这样我就可以在 localhost、lvh.me 和我将在生产中使用的任何域之间跳转,而无需继续编辑 session_store.rb 文件。但是,设置“域::所有”似乎对我不起作用。
Ultimately I found that I needed to state the tld_length (top level domain length) in that expression. The default tld_length is 1 while example.lvh.me has a tld_length of 2 and 127.0.0.1.xip.io has a tld_length of 5, for example. So what I had in the session_store.rb file for subdomains on lvh.me in development and whatever else in production was the below.
最终我发现我需要在该表达式中说明 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
Hope this helps someone, as it took me a long time to find this answer!
希望这对某人有所帮助,因为我花了很长时间才找到这个答案!
回答by Evan
For some reason replacing :allwith the domain did not work (rails 3.2.11) for me. It took a piece of custom Middleware to fix it. A summary of that solution is below.
由于某种原因,用:all域替换对我来说不起作用(rails 3.2.11)。它需要一个定制的中间件来修复它。该解决方案的摘要如下。
tl;dr:You need to write a custom Rack Middleware. You need add it into your conifg/environments/[production|development].rb. This is on Rails 3.2.11
tl;dr:您需要编写自定义机架中间件。您需要将其添加到您的conifg/environments/[production|development].rb. 这是在 Rails 3.2.11 上
Cookie sessions are usually stored only for your top level domain.
Cookie 会话通常只为您的顶级域存储。
If you look in Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}You can see that there will be separate entries for sub1.yourdomain.comand othersub.yourdomain.comand yourdomain.com
如果您查看Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}您可以看到将有单独的条目sub1.yourdomain.com和othersub.yourdomain.com和yourdomain.com
The challenge is to use the same session store file across all subdomains.
挑战是在所有子域中使用相同的会话存储文件。
Step 1: Add Custom Middleware Class
步骤 1:添加自定义中间件类
This is where Rack Middlewarecomes in. Some relevant rack & rails resources:
这就是机架中间件的用武之地。一些相关的机架和导轨资源:
- Railscasts about Rack
- Railsguide for Rack
- Rack documentation for sesssions abstractlyand for cookie sessions
Here is a custom class that you should add in the libThis was written by @Naderand you all should thank him
这是一个自定义类,您应该添加到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
Basically what this does is that it will map all of your cookie session data back onto the exact same cookie file that is equal to your root domain.
基本上,它的作用是将您的所有 cookie 会话数据映射回与您的根域完全相同的 cookie 文件。
Step 2: Add To Rails Config
第 2 步:添加到 Rails 配置
Now that you have a custom class in lib, make sure are autoloading it. If that meant nothing to you, look here: Rails 3 autoload
现在您在 lib 中有一个自定义类,请确保自动加载它。如果这对您来说毫无意义,请看这里:Rails 3 autoload
The first thing is to make sure that you are system-wide using a cookie store. In config/application.rbwe tell Rails to use a cookie store.
第一件事是确保您在系统范围内使用 cookie 存储。在config/application.rb我们告诉Rails使用cookie存储。
# We use a cookie_store for session data
config.session_store :cookie_store,
:key => '_yourappsession',
:domain => :all
The reason this is here is mentioned here is because of the :domain => :allline. There are other people that have suggested to specify :domain => ".yourdomain.com"instead of :domain => :all. For some reason this did not work for me and I needed the custom Middleware class as described above.
这里提到这里的原因是因为这:domain => :all条线。还有其他人建议指定:domain => ".yourdomain.com"而不是:domain => :all. 出于某种原因,这对我不起作用,我需要如上所述的自定义中间件类。
Then in your config/environments/production.rbadd:
然后在您config/environments/production.rb添加:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
Note that the preceding dot is necessary. See "sub-domain cookies, sent in a parent domain request?" for why.
请注意,前面的点是必需的。请参阅“在父域请求中发送的子域 cookie?”了解原因。
Then in your config/environments/development.rbadd:
然后在您config/environments/development.rb添加:
config.middleware.use "CustomDomainCookie", ".lvh.me"
The lvh.me trick maps onto localhost. It's awesome. See this Railscast about subdomainsand this notefor more info.
lvh.me 技巧映射到本地主机。这很棒。有关更多信息,请参阅有关子域的 Railscast和此注释。
Hopefully that should do it. I honestly am not entirely sure why the process is this convoluted, as I feel cross subdomain sites are common. If anyone has any further insights into the reasons behind each of these steps, please enlighten us in the comments.
希望应该这样做。老实说,我不完全确定为什么这个过程如此复杂,因为我觉得跨子域站点很常见。如果有人对每个步骤背后的原因有任何进一步的了解,请在评论中启发我们。
回答by cassanego
I came across this while looking for the simplest way to set the cookie to be the root domain. It seems there is some misinformation about the :alloption when passed as the domain option. For most domains, it will actually work as expected, setting the cookie to the root domain (e.g. .example.comfor test.example.com). I think most people experienced issues since they're using the domain lvh.meto test. The regex used by rails to find a top level domain is defined to be DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. If you note the last part, you can see that rails interprets lvh.meas a TLD similar to com.au. If your use case needs lvh.meto work, then the :alloption won't work properly, however, it appears to be the simplest and best option for most domains.
我在寻找将 cookie 设置为根域的最简单方法时遇到了这个问题。:all当作为域选项传递时,似乎有一些关于该选项的错误信息。对于大多数域,它实际上会按预期工作,将 cookie 设置为根域(例如.example.comfor test.example.com)。我认为大多数人都遇到过问题,因为他们使用域lvh.me进行测试。rails 用于查找顶级域的正则表达式定义为DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. 如果您注意最后一部分,您可以看到 rails 解释lvh.me为类似于com.au. 如果您的用例需要lvh.me工作,那么该:all选项将无法正常工作,但是,对于大多数域来说,它似乎是最简单和最佳的选项。
TL;DR, the correct answer here, assuming you aren't developing on a 3 letter domain (or any domain that confuses the above regex) is to use :all.
TL;DR,这里的正确答案是,假设您不是在 3 个字母的域(或任何混淆上述正则表达式的域)上开发,则使用:all.
回答by 7urkm3n
Rails 4.x(also should be fine with Rails 5/6 versions)
Rails 4.x(也应该适用于 Rails 5/6 版本)
How to get lvh.me:3000 and subdomain in localhost (Rails)
如何在本地主机(Rails)中获取 lvh.me:3000 和子域
Development: I have shared cookies to adding .lvh.meinto session_store.rb,
开发:我已共享 cookie 以添加.lvh.me到session_store.rb,
It will be shared between subdomains on localhost admin.lvh.me:3000, lvh.me:3000and so on...
它将在 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
回答by Naveed
Did you try
你试过了吗
AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'
)
)
basically we are saying have single cookie for base domain and just ignore sub domain..though this approach has some flaws still ...
基本上我们是说基域有单个 cookie 而只是忽略子域......虽然这种方法仍然有一些缺陷......
回答by cgg5207
support rails5
支撑导轨5
if you want it works with any domain:
如果您希望它适用于任何域:
Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: :all, tld_length: 2
To configure per environment you could use the following:
要配置每个环境,您可以使用以下内容:
Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: {
production: '.example.com',
development: '.example.dev'
}.fetch(Rails.env.to_sym, :all)
Ref: https://github.com/plataformatec/devise/wiki/How-To:-Use-subdomains
参考:https: //github.com/plataformatec/devise/wiki/How-To: -Use-subdomains

