¿Compartir sesión (cookies) entre subdominios en Rails?

92

Tengo una configuración de aplicación en la que cada usuario pertenece a una empresa, y esa empresa tiene un subdominio (estoy usando subdominios de estilo basecamp). El problema al que me enfrento es que los rieles están creando múltiples cookies (una para lvh.me y otra para subdominio.lvh.me), lo que está causando bastantes interrupciones en mi aplicación (como mensajes flash persistentes en todas las solicitudes una vez) registrado).

Tengo esto en mi archivo /cofig/initilizers/session_store.rb:

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

El dominio:: todo parece ser la respuesta estándar que encontré en Google, pero eso no parece funcionar para mí. ¡Se agradece cualquier ayuda!

Wahaj Ali
fuente

Respuestas:

74

Como resultado, 'dominio: todos' crea una cookie para todos los diferentes subdominios que se visitan durante esa sesión (y garantiza que se transmitan entre solicitudes). Si no se pasa ningún argumento de dominio, significa que se crea una nueva cookie para cada dominio diferente que se visita en la misma sesión y se descarta la anterior. Lo que necesitaba era una sola cookie que persista durante toda la sesión, incluso cuando cambia el dominio. Por lo tanto, aprobar domain: "lvh.me"resolvió el problema en desarrollo. Esto crea una sola cookie que permanece allí entre diferentes subdominios.

Para cualquiera que necesite más explicaciones, este es un gran enlace: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

Wahaj Ali
fuente
2
Gracias amigo .. He estado enfrentando este problema en uno de mis proyectos .. Finalmente encontré la solución ..
Shirjeel Alam
3
Asegúrate de usar el mismo config.secret_key_base en todas sus aplicaciones, o de lo contrario no podrá decodificar la cookie.
Bruno Buccolo
5
No veo ninguna pregunta relacionada con esto para Rails 4. ¿Sabes si esto ha cambiado? No puedo hacer que funcione con mi proyecto. Sigue recreando las cookies. Gracias.
Andy
¿Qué pasa si quiero usar CacheStorepara almacenar sesiones en memcached?
Amit Patel
2
Con Rails4, descubrí que esto solo funcionaba para subdominios con guiones pero no con guiones bajos: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/

"La parte que debe tener en cuenta aquí es que si establece: dominio =>: se recomienda todo como en algunos lugares, simplemente no funcionará a menos que esté usando localhost.: Todos los valores predeterminados para una longitud de TLD de 1 , lo que significa que si está probando con Pow (myapp.dev) tampoco funcionará porque es un TLD de longitud 2. "

En otras palabras, necesitas:

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

También es una buena idea borrar sus cookies

Montreal
fuente
1
Esta es la mejor respuesta porque el único cambio funciona en todos los entornos (app.com y app.dev). El middleware personalizado no es necesario. ¡También es un buen punto para borrar las cookies!
Turadg
1
te estás perdiendo el, :tld_length => 2
montrealmike
1
Asegúrese de usar el mismo config.secret_key_baseen todas sus aplicaciones, o de lo contrario no podrá decodificar la cookie.
Bruno Buccolo
4
:domain => :allno funcionará en Rails 4, inténtalo domain => 'lvh.me', tld_length = 2. Funcionó para mí
Minh Triet
1
Con Rails 4.2 obtuve buenos resultados con solo domain: :all, tld_length: 2usar el lvh.medominio.
zwippie
24

Estaba buscando una manera de resolver este problema sin tener que indicar explícitamente el nombre de dominio, para poder saltar entre localhost, lvh.me y cualquier dominio que usaría en producción sin tener que seguir editando el archivo session_store.rb. Sin embargo, la configuración de "dominio:: todos" no parecía funcionar para mí.

En última instancia, descubrí que necesitaba indicar tld_length (longitud del dominio de nivel superior) en esa expresión. El tld_length predeterminado es 1 mientras que example.lvh.me tiene un tld_length de 2 y 127.0.0.1.xip.io tiene un tld_length de 5, por ejemplo. Entonces, lo que tenía en el archivo session_store.rb para subdominios en lvh.me en desarrollo y cualquier otra cosa en producción fue el siguiente.

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

Espero que esto ayude a alguien, ¡ya que me tomó mucho tiempo encontrar esta respuesta!

ColmillosPeriquito
fuente
19

Por alguna razón, reemplazar :allcon el dominio no funcionó (rieles 3.2.11) para mí. Se necesitó una pieza de Middleware personalizado para solucionarlo. A continuación se muestra un resumen de esa solución.

tl; dr: Necesita escribir un Rack Middleware personalizado. Necesita agregarlo a su conifg/environments/[production|development].rb. Esto está en Rails 3.2.11

Las sesiones de cookies generalmente se almacenan solo para su dominio de nivel superior.

Si miras en Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}Puedes ver que habrá entradas separadas para sub1.yourdomain.comy othersub.yourdomain.comyyourdomain.com

El desafío consiste en utilizar el mismo archivo de almacenamiento de sesión en todos los subdominios.

Paso 1: agregar una clase de middleware personalizada

Aquí es donde entra en juego Rack Middleware . Algunos recursos de rack y rieles relevantes:

Aquí hay una clase personalizada que debe agregar en el lib Esto fue escrito por @Nader y todos deben agradecerle

# 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

Básicamente, lo que hace es que mapeará todos los datos de su sesión de cookies en el mismo archivo de cookies que es igual a su dominio raíz.

Paso 2: Agregar a la configuración de rieles

Ahora que tiene una clase personalizada en lib, asegúrese de cargarla automáticamente. Si eso no significa nada para usted, mire aquí: Autocarga de Rails 3

Lo primero es asegurarse de utilizar un almacén de cookies en todo el sistema. En config/application.rble decimos a Rails que use una tienda de cookies.

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

La razón por la que esto está aquí se menciona aquí es por la :domain => :alllínea. Hay otras personas que han sugerido especificar en :domain => ".yourdomain.com"lugar de :domain => :all. Por alguna razón, esto no funcionó para mí y necesitaba la clase Middleware personalizada como se describe anteriormente.

Luego en su config/environments/production.rbcomplemento:

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

Tenga en cuenta que el punto anterior es necesario. Consulte " Cookies de subdominio, ¿enviadas en una solicitud de dominio principal? " Para saber por qué.

Luego en su config/environments/development.rbcomplemento:

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

El truco lvh.me se asigna a localhost. Es impresionante. Consulte este Railscast sobre subdominios y esta nota para obtener más información.

Con suerte, debería hacerlo. Honestamente, no estoy del todo seguro de por qué el proceso es tan complicado, ya que creo que los sitios de subdominios cruzados son comunes. Si alguien tiene más información sobre las razones detrás de cada uno de estos pasos, infórmenos en los comentarios.

Evan
fuente
¿Hay alguna forma de hacer que esto funcione con varios dominios de nivel superior? Tengo un producto que funciona en diferentes países. Aquí asumimos que el dominio predeterminado es yourdomain.com, pero ¿y si se suponía que funcionara para .be .sv .fr .com.br .com.ar y otros? Gracias.
Marc Lainez
No puedo hacer que esto funcione. Estoy desarrollando en rieles 4 y parece que los rials simplemente ignoran suavemente todo el código anterior. Simplemente no quiere compartir la sesión entre subdominios.
Ole Henrik Skogstrøm
@ OleHenrikSkogstrøm Asegúrese de usar el mismo config.secret_key_baseen todas sus aplicaciones, o de lo contrario no podrá decodificar la cookie.
Bruno Buccolo
17

Me encontré con esto mientras buscaba la forma más sencilla de configurar la cookie para que sea el dominio raíz. Parece que hay información errónea sobre la :allopción cuando se pasa como opción de dominio. Para la mayoría de los dominios, funcionará como se esperaba, configurando la cookie en el dominio raíz (por ejemplo, .example.compara test.example.com). Creo que la mayoría de las personas experimentaron problemas porque están usando el dominio lvh.mepara realizar pruebas. La expresión regular utilizada por rieles para encontrar un dominio de nivel superior se define como DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/. Si observa la última parte, puede ver que rails se interpreta lvh.mecomo un TLD similar a com.au. Si su caso de uso necesita lvh.mefuncionar, entonces la :allopción no funcionará correctamente, sin embargo, parece ser la mejor y más simple opción para la mayoría de los dominios.

TL; DR, la respuesta correcta aquí, asumiendo que no está desarrollando en un dominio de 3 letras (o cualquier dominio que confunda la expresión regular anterior) es usar :all.

cassanego
fuente
Gracias, esto finalmente me ayudó a comprender por qué tantas respuestas recomendaban un tld_length de 2, ¡pero por qué no era necesario!
soupdog
Esta respuesta debe estar más arriba. Gracias Señor.
luca.bus el
"lvh.me como un TLD similar a com.au" Por cierto, Rails debería interpretar .me de la misma manera, ya que también es un dominio de país (Montenegro).
mahemoff
7

Rails 4.x (también debería funcionar con las versiones Rails 5/6)

Cómo obtener lvh.me:3000 y el subdominio en localhost (Rails)

Desarrollo: he compartido cookies para añadir .lvh.mea session_store.rb,

Se compartirá entre subdominios en localhost admin.lvh.me:3000 , lvh.me:3000y así sucesivamente ...

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

Has probado

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

)

Básicamente, estamos diciendo que tenga una sola cookie para el dominio base y simplemente ignore el subdominio ... aunque este enfoque todavía tiene algunos defectos ...

Naveed
fuente
1

rieles de soporte5

si quieres que funcione con cualquier dominio:

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

Para configurar por entorno, puede utilizar lo siguiente:

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
fuente
0

Si está utilizando Redis para almacenar sesiones.

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
fuente