Udostępniać sesje (pliki cookie) między subdomenami w Railsach?

93

Mam konfigurację aplikacji, w której każdy użytkownik należy do firmy, a ta firma ma subdomenę (używam subdomen w stylu basecamp). Problem, z którym się zmagam, polega na tym, że railsy tworzą wiele ciasteczek (jeden dla lvh.me, a drugi dla subdomain.lvh.me), co powoduje kilka przerw w mojej aplikacji (na przykład wiadomości flash są trwałe mimo wszystkich żądań raz zalogowany).

Mam to w moim pliku /cofig/initilizers/session_store.rb:

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

Domena:: all wydaje się być standardową odpowiedzią, którą znalazłem w Google, ale wydaje mi się, że nie działa. Każda pomoc jest mile widziana!

Wahaj Ali
źródło

Odpowiedzi:

76

Jak się okazuje, „domena: wszystko” tworzy plik cookie dla wszystkich różnych poddomen, które są odwiedzane podczas tej sesji (i zapewnia, że ​​są one przekazywane między żądaniami). Jeśli nie zostanie przekazany żaden argument domeny, oznacza to, że nowy plik cookie jest tworzony dla każdej innej domeny, która jest odwiedzana w tej samej sesji, a stara jest usuwana. Potrzebowałem jednego pliku cookie, który jest trwały przez całą sesję, nawet po zmianie domeny. Stąd zaliczenie domain: "lvh.me"rozwiązało problem w rozwoju. Tworzy to pojedynczy plik cookie, który pozostaje między różnymi subdomenami.

Dla każdego, kto potrzebuje dalszych wyjaśnień, jest to świetny link: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

Wahaj Ali
źródło
2
Dzięki, stary .. Miałem problem z jednym z moich projektów .. W końcu znalazłem rozwiązanie ..
Shirjeel Alam
3
Pamiętaj, aby używać tego samego config.secret_key_basewe wszystkich aplikacjach, w przeciwnym razie nie będzie w stanie zdekodować pliku cookie.
Bruno Buccolo
6
Nie widzę żadnych pytań związanych z tym dla Rails 4. Czy wiesz, czy to się zmieniło. Nie mogę zmusić go do pracy z moim projektem. Ciągle odtwarza pliki cookie. Dzięki.
Andy
A jeśli chcę CacheStoreprzechowywać sesje w memcached?
Amit Patel
2
Z Rails4 stwierdziłem, że działa to tylko dla subdomen z myślnikami, ale nie z podkreśleniami:Appname::Application.config.session_store :cookie_store, key: '_appname_session', domain: :all, tld_length: 2
user1515295
68

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

„Część, na którą chcesz tutaj zwrócić uwagę, to to, że jeśli ustawisz: domain =>: wszystko jak jest zalecane w niektórych miejscach, po prostu nie zadziała, chyba że używasz localhost.: Wszystkie domyślnie mają długość TLD 1 , co oznacza, że ​​jeśli testujesz za pomocą Pow (myapp.dev), to też nie zadziała, ponieważ jest to TLD o długości 2. ”

Innymi słowy, potrzebujesz:

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

Dobrym pomysłem jest również wyczyszczenie plików cookie

montrealmike
źródło
1
To najlepsza odpowiedź, ponieważ jedna zmiana działa we wszystkich środowiskach (app.com i app.dev). Niestandardowe oprogramowanie pośredniczące nie jest konieczne. Warto też wyczyścić pliki cookie!
Turadg
1
brakuje ci, :tld_length => 2
montrealmike
1
Pamiętaj, aby używać tego samego config.secret_key_basewe wszystkich aplikacjach, w przeciwnym razie nie będzie w stanie zdekodować pliku cookie.
Bruno Buccolo
4
:domain => :allnie zadziała w Rails 4, spróbuj domain => 'lvh.me', tld_length = 2. To zadziałało dla mnie
Minh Triet
1
Z Railsami 4.2 uzyskałem dobre wyniki tylko domain: :all, tld_length: 2podczas korzystania z lvh.medomeny.
zwippie
24

Szukałem sposobu na rozwiązanie tego problemu bez konieczności jawnego podawania nazwy domeny, aby móc przeskakiwać między localhost, lvh.me i dowolnymi domenami, których używałbym w produkcji, bez konieczności ciągłego edytowania pliku session_store.rb. Jednak ustawienie „domain:: all” nie wydaje się działać dla mnie.

Ostatecznie odkryłem, że muszę podać tld_length (długość domeny najwyższego poziomu) w tym wyrażeniu. Domyślną wartością tld_length jest 1, podczas gdy przykład.lvh.me ma wartość tld_length równą 2, a 127.0.0.1.xip.io ma na przykład tld_length równą 5. Więc to, co miałem w pliku session_store.rb dla subdomen na lvh.me w fazie rozwoju i cokolwiek innego w produkcji, było poniżej.

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

Mam nadzieję, że to komuś pomoże, ponieważ znalezienie tej odpowiedzi zajęło mi dużo czasu!

FangedParakeet
źródło
19

Z jakiegoś powodu podmiana :alldomeny nie zadziałała (szyny 3.2.11) u mnie. Naprawienie tego wymagało niestandardowego oprogramowania pośredniczącego. Podsumowanie tego rozwiązania znajduje się poniżej.

tl; dr: Musisz napisać niestandardowe oprogramowanie pośredniczące do stojaka. Musisz dodać to do swojego conifg/environments/[production|development].rb. To jest na Railsach 3.2.11

Sesje cookie są zwykle przechowywane tylko dla domeny najwyższego poziomu.

Jeśli zajrzysz do Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}środka, zobaczysz, że będą osobne wpisy dla sub1.yourdomain.comi othersub.yourdomain.comiyourdomain.com

Wyzwaniem jest użycie tego samego pliku magazynu sesji we wszystkich subdomenach.

Krok 1: Dodaj niestandardową klasę oprogramowania pośredniego

W tym miejscu pojawia się oprogramowanie pośredniczące do szaf serwerowych . Niektóre odpowiednie zasoby dotyczące szaf i szyn:

Oto niestandardowa klasa, którą powinieneś dodać w lib To zostało napisane przez @Nader i wszyscy powinniście mu podziękować

# 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

Zasadniczo powoduje to mapowanie wszystkich danych sesji plików cookie z powrotem do dokładnie tego samego pliku cookie, który jest równy domenie głównej.

Krok 2: Dodaj do konfiguracji Railsów

Teraz, gdy masz już klasę niestandardową w bibliotece, upewnij się, że ładujesz ją automatycznie. Jeśli to nic dla ciebie nie znaczyło, spójrz tutaj: Automatyczne ładowanie Rails 3

Pierwszą rzeczą jest upewnienie się, że korzystasz z magazynu plików cookie w całym systemie. W tym config/application.rbinformujemy Railsy, ​​aby używały magazynu plików cookie.

# We use a cookie_store for session data
config.session_store :cookie_store,
                     :key => '_yourappsession',
                     :domain => :all

Powodem, dla którego jest to tutaj wspomniane, jest :domain => :alllinia. Są inne osoby, które zasugerowały określenie :domain => ".yourdomain.com"zamiast :domain => :all. Z jakiegoś powodu to nie zadziałało i potrzebowałem niestandardowej klasy oprogramowania pośredniego, jak opisano powyżej.

Następnie w Twoim config/environments/production.rbdodatku:

config.middleware.use "CustomDomainCookie", ".yourdomain.com"

Zwróć uwagę, że poprzedzająca kropka jest konieczna. Zobacz temat „ Pliki cookie subdomeny wysłane w żądaniu domeny nadrzędnej? ”, Aby dowiedzieć się, dlaczego.

Następnie w Twoim config/environments/development.rbdodatku:

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

Sztuczka lvh.me jest mapowana na localhost. To jest zajebiste. Zobacz ten Railscast o subdomenach i tę notatkę po więcej informacji.

Mam nadzieję, że to powinno wystarczyć. Szczerze mówiąc, nie jestem do końca pewien, dlaczego ten proces jest tak zawiły, ponieważ uważam, że witryny krzyżowe z subdomenami są powszechne. Jeśli ktoś ma jakieś dodatkowe informacje na temat przyczyn każdego z tych kroków, prosimy o wyjaśnienie nas w komentarzach.

Evan
źródło
Czy istnieje sposób, aby to działało z wieloma domenami najwyższego poziomu? Mam produkt, który jest dostępny w różnych krajach. Tutaj zakładamy, że domena domyślna to twojadomena.com, ale co by było, gdyby miała działać dla .be .sv .fr .com.br .com.ar i innych? Dzięki.
Marc Lainez
Po prostu nie mogę zmusić tego do pracy. Rozwijam się w rails 4 i wygląda na to, że rials po prostu delikatnie ignoruje cały powyższy kod. Po prostu nie chce udostępniać sesji między subdomenami.
Ole Henrik Skogstrøm
@ OleHenrikSkogstrøm Pamiętaj, aby używać tego samego config.secret_key_basewe wszystkich aplikacjach, w przeciwnym razie nie będzie w stanie zdekodować pliku cookie.
Bruno Buccolo
17

Natknąłem się na to, szukając najprostszego sposobu, aby ustawić plik cookie jako domenę główną. Wygląda na to, że istnieje pewne błędne informacje na temat :allopcji, która jest przekazywana jako opcja domeny. W przypadku większości domen będzie działać zgodnie z oczekiwaniami, ustawiając plik cookie na domenę główną (np. .example.comDla test.example.com). Myślę, że większość ludzi napotkała problemy, ponieważ używają domeny lvh.medo testowania. Wyrażenie regularne używane przez railsy do znalezienia domeny najwyższego poziomu jest zdefiniowane jako DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. Jeśli zwrócisz uwagę na ostatnią część, zobaczysz, że railsy interpretują lvh.mejako TLD podobne do com.au. Jeśli Twój przypadek użycia musi lvh.medziałać, :allopcja nie będzie działać poprawnie, jednak wydaje się, że jest to najprostsza i najlepsza opcja dla większości domen.

TL; DR, poprawna odpowiedź tutaj, zakładając, że nie tworzysz w domenie 3-literowej (lub jakiejkolwiek domenie, która myli powyższe wyrażenie regularne), to użycie :all.

cassanego
źródło
Dziękuję, to w końcu pomogło mi zrozumieć, dlaczego tak wiele odpowiedzi zalecało tld_length równą 2, ale dlaczego nie musiałem!
pies pasterski
Ta odpowiedź musi być wyżej. Dziekuje panu.
luca.busin
„lvh.me jako TLD podobna do com.au” BTW Rails powinny rzeczywiście interpretować .me w taki sam sposób, jak jest to również domena krajowa (Czarnogóra).
mahemoff
8

Rails 4.x (powinno również pasować do wersji Rails 5/6)

Jak zdobyć lvh.me:3000 i subdomenę w localhost (Rails)

Opracowanie: I mają wspólne cookies w celu dodania .lvh.medo session_store.rb,

Zostanie on podzielony między subdomen na localhost admin.lvh.me:3000, lvh.me:3000i tak dalej ...

#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
7urkm3n
źródło
4

Próbowałeś

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

)

w zasadzie mówimy, że mamy jeden plik cookie dla domeny podstawowej i po prostu ignorujemy domenę podrzędną ... chociaż to podejście ma nadal pewne wady ...

Naveed
źródło
2

szyny nośne 5

jeśli chcesz, aby działał z każdą domeną:

Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: :all, tld_length: 2

Aby skonfigurować środowisko, możesz użyć następujących elementów:

Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: {
  production: '.example.com',
  development: '.example.dev'
}.fetch(Rails.env.to_sym, :all)

Odniesienie: https://github.com/plataformatec/devise/wiki/How-To:-Use-subdomains

cgg5207
źródło
0

Jeśli używasz Redis do przechowywania sesji.

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 
Marcelo Austria
źródło