Поділити сеанс (файли cookie) між субдоменами в Rails?


92

У мене встановлена ​​програма, де кожен користувач належить компанії, і ця компанія має субдомен (я використовую субдомени стилю 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, але, здається, це не працює для мене. Будь-яка допомога вдячна!

Відповіді:


74

Як виявляється, 'domain: all' створює файл 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.
Бруно Букколо

5
Я не бачу жодних питань, пов’язаних з цим щодо Rails 4. Чи знаєте ви, чи це змінилося? Я не можу змусити його працювати зі своїм проектом. Він продовжує відтворювати печиво. Дякую.
Енді,

Що робити, якщо я хочу використовувати CacheStoreдля зберігання сеансів у memcached?
Amit Patel

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 =>: все, як рекомендується в деяких місцях, це просто не буде працювати, якщо ви не використовуєте localhost.: За замовчуванням довжина TLD становить 1 , це означає, що якщо ви тестуєте за допомогою Pow (myapp.dev), він також не буде працювати, оскільки це TLD довжини 2. "

Іншими словами, вам потрібно:

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

Також непогана ідея очистити файли cookie


1
Це найкраща відповідь, оскільки одна зміна працює у всіх середовищах (app.com та app.dev). Спеціальне проміжне програмне забезпечення не потрібно. Також хороший момент, щоб очистити файли cookie!
Турадг

1
ви пропускаєте, :tld_length => 2
montrealmike

1
Обов’язково використовуйте те саме config.secret_key_baseдля всіх своїх програм, інакше він не зможе декодувати файл cookie.
Бруно Букколо

4
:domain => :allне буде працювати в Rails 4, спробуйте domain => 'lvh.me', tld_length = 2. Це спрацювало для мене
Minh Triet

1
За допомогою Rails 4.2 я отримав хороші результати лише domain: :all, tld_length: 2під час використання lvh.meдомену.
zwippie 01.03.15

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на домен для мене не спрацювала (рейки 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

Проблема полягає у використанні одного і того ж файлу сховища сеансів у всіх субдоменах.

Крок 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 Config

Тепер, коли у вас є власний клас у lib, переконайтеся, що ви завантажуєте його автоматично. Якщо це для вас нічого не означало, дивіться тут: Rails 3 autoload

Перше, що потрібно, щоб переконатись, що ти використовуєш загальносистемну систему, використовуючи магазин печива. В 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. З якоїсь причини це не спрацювало для мене, і мені потрібен був власний клас Middleware, як описано вище.

Потім у своєму 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 про субдомени та цю примітку .

Сподіваємось, це повинно це зробити. Я, чесно кажучи, не зовсім впевнений, чому процес такий заплутаний, оскільки я відчуваю, що сайти між субдоменами є загальними. Якщо хтось має подальше розуміння причин кожного з цих кроків, будь ласка, поясніть нам у коментарях.


Чи є спосіб зробити цю роботу з кількома доменами верхнього рівня? У мене є продукт, який працює в різних країнах. Тут ми припускаємо, що типовим доменом є ваш домен.com, але що, якби він мав працювати для .be .sv .fr .com.br .com.ar та інших? Дякую.
Marc Lainez

Я просто не можу змусити це працювати. Я розробляю в rails 4, і здається, що ріали просто обережно ігнорують весь наведений вище код. Він просто не хоче ділитися сеансом між субдоменами.
Ole Henrik Skogstrøm

@ 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, тут слід використовувати правильну відповідь, припускаючи, що ви не розробляєте 3-літерний домен (або будь-який домен, який заплутує вищезазначений регулярний вираз) :all.


Дякую, це нарешті допомогло мені зрозуміти, чому так багато відповідей рекомендували tld_length 2, але чому мені це не потрібно було!
супдог

Ця відповідь повинна бути вище. Дякую, сер.
luca.busin

"lvh.me як TLD, подібний до com.au". BTW Rails дійсно повинен інтерпретувати .me так само, як це також домен країни (Чорногорія).
mahemoff

7

Rails 4.x (також має відповідати версіям Rails 5/6)

Як отримати lvh.me:3000 та субдомен у localhost (Rails)

Розвиток: Я ділилася куки для додавання .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

4

Ви пробували

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

)

в основному ми говоримо, що маємо єдиний файл cookie для базового домену і просто ігноруємо піддомен ... хоча цей підхід все ще має деякі недоліки ...


1

опорні рейки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


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 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.