Usando Express y Node, cómo mantener una sesión en subdominios / hostheaders

Tengo un servidor de nodo único que responde a las solicitudes y redirige a un usuario en función de los encabezados del host. El uso es que el sitio estático / home vive en www y cada usuario tiene su propio subdominio (es decir, www.example.com y site.example.com). El enrutamiento es según site.js.

Cuando el usuario no está conectado, se le redirige para iniciar sesión.

Estoy descubriendo que la sesión no se mantiene cuando el usuario es redirigido a su subdominio. Supongo que esto se espera, pero me pregunto si hay una forma de mantener la misma sesión en ambos subdominios.

Tenía la esperanza de que si estuvieran conectados y volvieran a www.example.com verían una vista diferente que incluyera un enlace para cerrar la sesión / su tablero, etc. Mi solución en este momento, estoy pensando, es simplemente crear la sesión en su subdominio y si vuelven a www será como si no hubieran iniciado sesión.

¿Alguien ha tratado esto antes o tiene respuestas sobre cómo manejar sesiones de esta manera?

Creo que el problema puede estar en users.js, donde redirecciono a ‘http://site.example.com’ ya que no es una ruta relativa …

Aquí está el código relevante (la búsqueda del usuario se hace usando MongoDB y lo dejé porque funciona bien, la línea que llama a este servicio es users.authenticate) …

server.js:

app.configure -> app.set "views", "#{__dirname}/views" app.set "view engine", "jade" app.use express.bodyParser() app.use express.methodOverride() app.use express.cookieParser() app.use express.session { key: "KEY", secret: "SECRET", store: new MemoryStore(), cookie: { domain: 'example.com', maxAge : 1000*60*60*24*30*12 } } app.use express.static "#{__dirname}/public" app.use express.logger "short" app.use express.favicon "#{__dirname}/public/img/favicon.ico" app.use app.router 

site.js:

 module.exports = (app) -> app.get '/', (req, res) -> console.log "/ hit with #{req.url} from #{req.headers.host}" domains = req.headers.host.split "." org = if domains then domains[0] else "www" if org == "www" res.render "index", { layout: null } else if req.session.user console.log "session established" res.render "app", { layout: null } else console.log "no session" res.redirect "http://www.example.com/accounts/login" 

users.js:

 users = require('../services/users') module.exports = (app) -> app.get "/accounts/login", (req, res) -> res.render "login", { layout: null, locals: { returnUrl: req.query.returnUrl } } app.post "/accounts", (req, res) -> users.authenticate app, req.body.login, req.body.password, (user) -> if user req.session.user = user res.redirect "http://#{user.orgName}.example.com" else res.render "login", { layout: null, locals: { returnUrl: req.body.url } } app.get "/accounts/logout", (req, res) -> console.log "deleting user from session" delete req.session.user res.redirect "http://www.example.com 

Para probarlo localmente en OSX, agregué www.example.com y site.example.com en mi archivo de hosts para que las búsquedas DNS se manejen localmente.

En primer lugar, para permitir que el navegador realice solicitudes entre dominios, debe establecer encabezados en el servidor. Esta solución funciona para solicitud normal y AJAX. En su función de configuración expresa:

Express 4.0 :

 var express = require('express'); var session = require('express-session'); var cookieParser = require('cookie-parser'); var app = express(); app.use(cookieParser()); app.use(session({ secret: 'yoursecret', cookie: { path: '/', domain: 'yourdomain.com', maxAge: 1000 * 60 * 24 // 24 hours } })); app.use(function(req, res, next) { res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Origin', req.headers.origin); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'); next(); }); 

Access-Control-Allow-Origin se puede establecer en ‘*’ si no se necesitan intercambios de cookies entre dominios para las sesiones necesarias. Para tener las cookies y la sesión compartida entre dominios, debe establecer el control de acceso-permitir-origen específico en el dominio en el que se realiza la solicitud, es por eso que req.headers.origin es perfecto para eso.

Usar el dominio no funcionará bien en localhost, por lo tanto, asegúrese de desactivarlo en el entorno de desarrollo y habilitarlo en la producción. Permitirá cookies compartidas en los principales y subdominios.

Esto no es todo. Los navegadores en sí no enviarán cookies a través de solicitudes de dominios cruzados, y esto tiene que ser forzado. En jQuery puedes agregar un parámetro adicional en la solicitud $ .ajax ():

 xhrFields: { withCredentials: true } 

Para no jQuery, solo tienes el constructor XHR y establece este parámetro:

 xhr.withCredentials = true; 

Y está listo para hacer dominios cruzados con sesión compartida.

¿Se aseguró de tener sus cookies establecidas en el dominio de nivel superior para que todos los subdominios puedan leerlas? Entonces solo es cuestión de persistir los datos de la sesión en la memoria, un DB, lo que sea como siempre. No tengo mi máquina de desarrollo en funcionamiento, pero será algo así en tu app.configure ().

 app.use(express.cookieParser()); app.use(express.session({ key: 'A_SESSION_KEY', secret: 'SOMETHING_REALLY_HARD_TO_GUESS', store: new express.session.MemoryStore, cookie: { path : '/', domain : 'yourdomain.com', httpOnly : true, maxAge : 1000*60*60*24*30*12 //one year(ish) } })); 

Nota: si usa Express 4 y el nuevo módulo de sesión de cookie, el código se ve como

 { secret:  , store:  , domain: '.domain.com', } 

Esto me mordió, pero la API ha cambiado.