Sitzung (Cookies) zwischen Subdomains in Rails teilen?

91

Ich habe ein App-Setup, bei dem jeder Benutzer einer Firma angehört und diese Firma eine Subdomain hat (ich verwende Subdomains im Basislager-Stil). Das Problem, mit dem ich konfrontiert bin, besteht darin, dass Rails mehrere Cookies erstellt (eines für lvh.me und eines für subdomain.lvh.me), was zu einigen Unterbrechungen in meiner Anwendung führt (z. B. Flash-Nachrichten, die bei allen Anforderungen einmal bestehen bleiben angemeldet).

Ich habe dies in meiner Datei /cofig/initilizers/session_store.rb:

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

Die Domain :: Alles scheint die Standardantwort zu sein, die ich bei Google gefunden habe, aber das scheint bei mir nicht zu funktionieren. Jede Hilfe wird geschätzt!

Wahaj Ali
quelle

Antworten:

73

Wie sich herausstellt, erstellt 'domain: all' ein Cookie für alle verschiedenen Subdomains, die während dieser Sitzung besucht werden (und stellt sicher, dass sie zwischen den Anforderungen weitergegeben werden). Wenn kein Domain-Argument übergeben wird, bedeutet dies, dass für jede andere Domain, die in derselben Sitzung besucht wird, ein neues Cookie erstellt wird und das alte verworfen wird. Was ich brauchte, war ein einzelnes Cookie, das während der gesamten Sitzung dauerhaft ist, auch wenn sich die Domäne ändert. Daher domain: "lvh.me"löste das Bestehen das Problem in der Entwicklung. Dadurch wird ein einzelnes Cookie erstellt, das zwischen verschiedenen Subdomains verbleibt.

Für alle, die weitere Erklärungen benötigen, ist dies ein großartiger Link: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

Wahaj Ali
quelle
2
Danke Dude .. Ich habe dieses Problem bei einem meiner Projekte gesehen .. Endlich die Lösung gefunden ..
Shirjeel Alam
3
Stellen Sie sicher, dass Sie config.secret_key_basein allen Anwendungen dasselbe verwenden , da sonst das Cookie nicht dekodiert werden kann.
Bruno Buccolo
5
Ich sehe keine diesbezüglichen Fragen für Rails 4. Wissen Sie, ob sich dies geändert hat? Ich kann es nicht dazu bringen, mit meinem Projekt zu arbeiten. Die Cookies werden immer wieder neu erstellt. Vielen Dank.
Andy
Was ist, wenn ich CacheStoreSitzungen in Memcached speichern möchte ?
Amit Patel
2
Mit Rails4 fand ich, dass dies nur für Subdomains mit Bindestrichen, aber nicht mit Unterstrichen Appname::Application.config.session_store :cookie_store, key: '_appname_session', domain: :all, tld_length: 2
funktionierte
65

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

"Der Teil, auf den Sie hier achten möchten, ist, dass wenn Sie Folgendes festlegen: domain =>: all like wird an einigen Stellen empfohlen, es einfach nicht funktioniert, wenn Sie localhost verwenden .: Alle standardmäßig eine TLD-Länge von 1 Das heißt, wenn Sie mit Pow (myapp.dev) testen, funktioniert es auch nicht, da dies eine TLD der Länge 2 ist. "

Mit anderen Worten, Sie brauchen:

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

Auch eine gute Idee, um Ihre Cookies zu löschen

montrealmike
quelle
1
Dies ist die beste Antwort, da die eine Änderung in allen Umgebungen (app.com und app.dev) funktioniert. Benutzerdefinierte Middleware ist nicht erforderlich. Auch ein guter Punkt, um Cookies zu löschen!
Turadg
1
Sie vermissen die, :tld_length => 2
montrealmike
1
Stellen Sie sicher, dass Sie config.secret_key_basein allen Anwendungen dasselbe verwenden , da sonst das Cookie nicht dekodiert werden kann.
Bruno Buccolo
4
:domain => :allfunktioniert nicht in Rails 4, versuchen Sie es domain => 'lvh.me', tld_length = 2. Es hat für mich funktioniert
Minh Triet
1
Mit Rails 4.2 habe ich gerade domain: :all, tld_length: 2bei der Nutzung der lvh.meDomain gute Ergebnisse erzielt .
zwippie
24

Ich suchte nach einer Möglichkeit, dieses Problem zu lösen, ohne den Domänennamen explizit angeben zu müssen, damit ich zwischen localhost, lvh.me und den Domänen wechseln konnte, die ich in der Produktion verwenden würde, ohne die Datei session_store.rb weiter bearbeiten zu müssen. Die Einstellung "domain :: all" schien jedoch nicht für mich zu funktionieren.

Letztendlich stellte ich fest, dass ich die tld_length (Domänenlänge der obersten Ebene) in diesem Ausdruck angeben musste. Die Standard-tld_length ist 1, während example.lvh.me eine tld_length von 2 und 127.0.0.1.xip.io beispielsweise eine tld_length von 5 hat. Was ich also in der Datei session_store.rb für Subdomains auf lvh.me in der Entwicklung und was auch immer in der Produktion hatte, war das Folgende.

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

Hoffe das hilft jemandem, da ich lange gebraucht habe, um diese Antwort zu finden!

FangedParakeet
quelle
19

Aus irgendeinem Grund :allfunktionierte das Ersetzen durch die Domain bei mir nicht (Rails 3.2.11). Es dauerte ein Stück benutzerdefinierte Middleware, um das Problem zu beheben. Eine Zusammenfassung dieser Lösung finden Sie unten.

tl; dr: Sie müssen eine benutzerdefinierte Rack-Middleware schreiben. Sie müssen es in Ihre hinzufügen conifg/environments/[production|development].rb. Dies ist auf Schienen 3.2.11

Cookie-Sitzungen werden normalerweise nur für Ihre Top-Level-Domain gespeichert.

Wenn Sie nachsehen, Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}können Sie sehen, dass es separate Einträge für sub1.yourdomain.comund othersub.yourdomain.comund gibtyourdomain.com

Die Herausforderung besteht darin, in allen Subdomänen dieselbe Sitzungsspeicherdatei zu verwenden.

Schritt 1: Fügen Sie eine benutzerdefinierte Middleware-Klasse hinzu

Hier kommt Rack Middleware ins Spiel . Einige relevante Rack & Rails-Ressourcen:

Hier ist eine benutzerdefinierte Klasse, die Sie hinzufügen sollten. lib Dies wurde von @Nader geschrieben und Sie alle sollten ihm danken

# 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

Im Grunde bedeutet dies, dass alle Ihre Cookie-Sitzungsdaten wieder genau derselben Cookie-Datei zugeordnet werden, die Ihrer Stammdomäne entspricht.

Schritt 2: Zu Schienen hinzufügen Konfiguration

Nachdem Sie eine benutzerdefinierte Klasse in lib haben, stellen Sie sicher, dass diese automatisch geladen wird. Wenn Ihnen das nichts bedeutet hat, schauen Sie hier: Rails 3 Autoload

Stellen Sie zunächst sicher, dass Sie mithilfe eines Cookie-Speichers systemweit sind. In config/application.rbsagen wir Rails, dass sie einen Cookie-Laden benutzen sollen.

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

Der Grund, warum dies hier erwähnt wird, liegt in der :domain => :allLinie. Es gibt andere Personen, die vorgeschlagen haben, :domain => ".yourdomain.com"anstelle von anzugeben:domain => :all . Aus irgendeinem Grund funktionierte dies bei mir nicht und ich benötigte die benutzerdefinierte Middleware-Klasse wie oben beschrieben.

Dann config/environments/production.rbfügen Sie hinzu:

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

Beachten Sie, dass der vorhergehende Punkt erforderlich ist. Weitere Informationen finden Sie unter " Subdomain-Cookies, die in einer übergeordneten Domain-Anfrage gesendet wurden? ".

Dann config/environments/development.rbfügen Sie hinzu:

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

Der Trick lvh.me wird auf localhost abgebildet. Es ist toll. Weitere Informationen finden Sie in diesem Railscast zu Subdomains und in diesem Hinweis .

Hoffentlich sollte es das tun. Ich bin mir ehrlich gesagt nicht ganz sicher, warum der Prozess so kompliziert ist, da ich der Meinung bin, dass Cross-Subdomain-Sites häufig sind. Wenn jemand weitere Einblicke in die Gründe für jeden dieser Schritte hat, klären Sie uns bitte in den Kommentaren auf.

Evan
quelle
Gibt es eine Möglichkeit, dies mit mehreren Top-Level-Domains zum Laufen zu bringen? Ich habe ein Produkt, das in verschiedenen Ländern läuft. Hier nehmen wir an, dass die Standarddomain yourdomain.com ist, aber was ist, wenn sie für .be .sv .fr .com.br .com.ar und andere funktionieren soll? Vielen Dank.
Marc Lainez
Ich kann das einfach nicht zum Laufen bringen. Ich entwickle in Rails 4 und es scheint, als würde Rials den gesamten obigen Code nur vorsichtig ignorieren. Es möchte die Sitzung einfach nicht über Subdomänen hinweg teilen.
Ole Henrik Skogstrøm
@ OleHenrikSkogstrøm Stellen Sie sicher, dass Sie config.secret_key_basein allen Anwendungen dasselbe verwenden , da sonst das Cookie nicht dekodiert werden kann.
Bruno Buccolo
17

Ich bin darauf gestoßen, als ich nach dem einfachsten Weg gesucht habe, das Cookie als Root-Domain festzulegen. Es scheint, dass es einige Fehlinformationen über die :allOption gibt, wenn sie als Domänenoption übergeben wird. Bei den meisten Domains funktioniert es tatsächlich wie erwartet und setzt das Cookie auf die Root-Domain (z . B. .example.comfür test.example.com). Ich denke, die meisten Leute hatten Probleme, da sie die Domain lvh.mezum Testen verwenden. Der reguläre Ausdruck, der von Rails verwendet wird, um eine Domäne der obersten Ebene zu finden, ist definiert als DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. Wenn Sie den letzten Teil notieren, können Sie sehen, dass Schienen lvh.meals TLD ähnlich interpretiert werden com.au. Wenn Ihr Anwendungsfall lvh.mefunktionieren muss, dann ist der:all Option nicht ordnungsgemäß. Sie scheint jedoch für die meisten Domänen die einfachste und beste Option zu sein.

TL; DR, die richtige Antwort hier, vorausgesetzt, Sie entwickeln nicht auf einer 3-Buchstaben-Domain (oder einer Domain, die den obigen regulären Ausdruck verwirrt), ist zu verwenden :all.

Cassanego
quelle
Vielen Dank, dies hat mir endlich geholfen zu verstehen, warum so viele Antworten eine tld_length von 2 empfehlen, aber warum ich es nicht brauchte!
soupdog
Diese Antwort muss höher sein. Danke, Sir.
luca.busin
"lvh.me als TLD ähnlich wie com.au" BTW Rails sollte .me in der Tat genauso interpretieren, wie es auch eine Länderdomäne (Montenegro) ist.
Mahemoff
7

Rails 4.x (sollte auch mit Rails 5/6-Versionen in Ordnung sein)

So erhalten Sie lvh.me:3000 und Subdomain in localhost (Rails)

Entwicklung: Ich habe Cookies zum Hinzufügen .lvh.mein geteilt session_store.rb,

Es wird zwischen Subdomains auf localhost geteilt admin.lvh.me:3000.lvh.me:3000 und so weiter ...

#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
quelle
4

Hast du versucht

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

)

Grundsätzlich sagen wir, haben Sie ein einzelnes Cookie für die Basisdomäne und ignorieren Sie einfach die Unterdomäne. Obwohl dieser Ansatz noch einige Mängel aufweist ...

Naveed
quelle
1

Stützschienen5

Wenn Sie möchten, funktioniert es mit jeder Domain:

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

Zum Konfigurieren pro Umgebung können Sie Folgendes verwenden:

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

cgg5207
quelle
0

Wenn Sie Redis für den Sitzungsspeicher verwenden.

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 Österreich
quelle