Разделять сеанс (файлы cookie) между поддоменами в Rails?

93

У меня есть настройка приложения, в которой каждый пользователь принадлежит компании, и у этой компании есть поддомен (я использую поддомены в стиле 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

Домен:: все кажется стандартным ответом, который я нашел в Google, но, похоже, это не работает для меня. Любая помощь приветствуется!

Вахадж Али
источник

Ответы:

76

Оказывается, «домен: все» создает cookie для всех различных поддоменов, которые посещаются во время этого сеанса (и это гарантирует, что они передаются между запросами). Если аргумент домена не передан, это означает, что новый файл cookie создается для каждого другого домена, который посещается в одном сеансе, а старый удаляется. Мне был нужен один файл cookie, который будет сохраняться в течение всего сеанса, даже когда домен изменяется. Значит, переход domain: "lvh.me"решил проблему в разработке. Это создает один файл cookie, который остается между разными поддоменами.

Для тех, кому нужны дополнительные объяснения, это отличная ссылка: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

Вахадж Али
источник
2
Спасибо, чувак .. Я столкнулся с этой проблемой в одном из моих проектов .. Наконец-то нашел решение ..
Ширджил Алам
3
Обязательно используйте одно и то же config.secret_key_baseво всех своих приложениях, иначе он не сможет декодировать cookie.
Бруно Букколо
6
Я не вижу вопросов по этому поводу для Rails 4. Вы знаете, изменилось ли это? Я не могу заставить его работать с моим проектом. Он продолжает создавать файлы cookie. Спасибо.
Энди
Что, если я хочу использовать CacheStoreдля хранения сессий в memcached?
Амит Патель,
2
С Rails4 я обнаружил, что это работает только для поддоменов с дефисами, но не с подчеркиванием:Appname::Application.config.session_store :cookie_store, key: '_appname_session', domain: :all, tld_length: 2
user1515295 02
68

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

"Здесь вы хотите обратить внимание на то, что если вы установите: domain =>: all like is Рекомендуется в некоторых местах, это просто не будет работать, если вы не используете localhost.: All по умолчанию имеет длину TLD 1 , что означает, что если вы тестируете Pow (myapp.dev), он тоже не будет работать, потому что это TLD длины 2. "

Другими словами, вам необходимо:

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

Также неплохо очистить файлы cookie

Монреальмайк
источник
1
Это лучший ответ, потому что одно изменение работает во всех средах (app.com и app.dev). Специальное промежуточное ПО не требуется. Также хороший момент для очистки файлов cookie!
Turadg
1
вы скучаете по, :tld_length => 2
montrealmike
1
Обязательно используйте одно и то же config.secret_key_baseво всех своих приложениях, иначе он не сможет декодировать cookie.
Бруно Букколо
4
:domain => :allне будет работать в Rails 4, попробуйте domain => 'lvh.me', tld_length = 2. Это сработало для меня
Мин Чиет
1
С Rails 4.2 я добился хороших результатов, просто domain: :all, tld_length: 2используя lvh.meдомен.
zwippie 01
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. Итак, что у меня было в файле session_store.rb для поддоменов на lvh.me в разработке и всего остального в производстве, было ниже.

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

Надеюсь, это поможет кому-то, так как мне потребовалось много времени, чтобы найти этот ответ!

КлыкастыйПракет
источник
19

Почему-то :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 . Некоторые соответствующие ресурсы для стоек и направляющих:

Вот пользовательский класс, который вы должны добавить в 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

Во-первых, убедитесь, что вы используете хранилище файлов cookie для всей системы. В config/application.rbмы говорим Rails использовать куки - магазин.

# 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 о субдоменах и эту заметку для получения дополнительной информации.

Надеюсь, это должно сработать. Честно говоря, я не совсем уверен, почему этот процесс такой запутанный, поскольку я считаю, что сайты с перекрестными поддоменами являются обычным явлением. Если у кого-то есть какие-либо дополнительные сведения о причинах каждого из этих шагов, сообщите нам об этом в комментариях.

Эван
источник
Есть ли способ заставить эту работу работать с несколькими доменами верхнего уровня? У меня есть продукт, который продается в разных странах. Здесь мы предполагаем, что доменом по умолчанию является yourdomain.com, но что, если он должен работать для .be .sv .fr .com.br .com.ar и других? Спасибо.
Marc Lainez
Я просто не могу заставить это работать. Я разрабатываю в rails 4, и кажется, что риал просто мягко игнорирует весь приведенный выше код. Он просто не хочет разделять сеанс между поддоменами.
Ole Henrik Skogstrøm 03
@ OleHenrikSkogstrøm Обязательно используйте одно и то же config.secret_key_baseво всех своих приложениях, иначе он не сможет декодировать cookie.
Бруно Букколо
17

Я столкнулся с этим, когда искал простейший способ сделать cookie корневым доменом. Кажется, есть некоторая дезинформация об :allопции, когда она передается как опция домена. Для большинства доменов это действительно будет работать должным образом, установив cookie в корневой домен (например, .example.comдля test.example.com). Я думаю, что у большинства людей возникли проблемы, поскольку они использовали домен lvh.meдля тестирования. Регулярное выражение, используемое rails для поиска домена верхнего уровня, определяется как DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. Если вы обратите внимание на последнюю часть, вы увидите, что rails интерпретируется lvh.meкак TLD, аналогичный com.au. Если ваш вариант использования должен lvh.meработать, этот :allвариант не будет работать должным образом, однако он кажется самым простым и лучшим вариантом для большинства доменов.

TL; DR, правильный ответ здесь, если вы не разрабатываете трехбуквенный домен (или любой домен, который сбивает с толку вышеуказанное регулярное выражение) :all.

кассанего
источник
Спасибо, это наконец помогло мне понять, почему так много ответов рекомендуют tld_length равное 2, но почему мне это не нужно!
soupdog
Этот ответ должен быть выше. Спасибо, сэр.
luca.busin 09
"lvh.me как TLD, подобный com.au" BTW Rails действительно должен интерпретировать .me так же, как это также домен страны (Черногория).
mahemoff
8

Rails 4.x (также должно работать с версиями Rails 5/6)

Как получить lvh.me:3000 и поддомен в localhost (Rails)

Разработка: я предоставил доступ к файлам cookie для добавления .lvh.meв session_store.rb,

Она будет разделена между поддоменами на локальном хосте 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
7уркм3н
источник
4

Ты пробовал

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

)

в основном мы говорим, что для базового домена нужно использовать один файл cookie и просто игнорировать субдомен ... хотя этот подход все еще имеет некоторые недостатки ...

Навид
источник
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

cgg5207
источник
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 
Марсело Австрия
источник