2012-01-30 5 views
11

Ho un singolo server nodo che risponde alle richieste e reindirizza un utente in base alle intestazioni host. L'uso è che il sito statico/home vive su www e ogni utente ha il proprio sottodominio (ad esempio www.example.com e site.example.com). Il routing è come per site.js.Utilizzo di Express e Node, come mantenere una sessione tra sottodomini/hosthead

Quando l'utente non ha effettuato l'accesso, viene reindirizzato per accedere.

Sto scoprendo che la sessione non viene mantenuta quando l'utente viene reindirizzato al proprio sottodominio. Immagino che questo è previsto, ma mi chiedo se c'è un modo per mantenere la stessa sessione su entrambi i sottodomini.

Speravo che se avessero effettuato il login e fossero tornati su www.example.com avrebbero visto una vista diversa che includeva un link per il logout/il loro cruscotto, ecc. La mia soluzione al momento, sto pensando, è solo creare la sessione sul loro sottodominio e se ritornano a www sarà come se non fossero loggati.

Chi ha avuto a che fare prima o ha risposte su come gestire le sessioni in questo modo?

Credo che il problema può essere in users.js dove reindirizzare a 'http://site.example.com' come il suo non è un percorso relativo ...

Ecco il relativo codice (l'utente ricerca viene fatto usando MongoDB e ho lasciato fuori come il suo bel lavoro - la linea che chiama questo servizio è 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     

verificarlo a livello locale su OSX, ho aggiunto www.example.com e site.example.com al mio file hosts in modo che le ricerche DNS vengono gestite localmente.

risposta

23

Prima di tutto per consentire al browser di effettuare richieste tra domini è necessario impostare le intestazioni sul lato server. Questa soluzione funziona sia per le normali richieste che per AJAX. Nella funzione di configurazione espresso:

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 può essere impostato a '*' se nessuno scambio cookie tra domini per le sessioni necessario. Per fare in modo che i cookie e la sessione siano condivisi tra domini è necessario impostare Access-Control-Allow-Origin specifico per il dominio da cui viene effettuata la richiesta, ecco perché req.headers.origin - è perfetto per questo.

L'utilizzo del dominio non funziona bene su localhost, quindi assicurati di disattivarlo nell'ambiente di sviluppo e abilitare in fase di produzione. Abiliterà i cookie condivisi tra i domini top e sub.

Questo non è tutto. I browser autonomamente non invieranno cookie su richieste interdominio e questo deve essere forzato. In jQuery è possibile aggiungere il parametro in più in $ .ajax() Richiesta:

xhrFields: { withCredentials: true } 

Per non jQuery, basta avere costruttore XHR e impostare questo parametro:

xhr.withCredentials = true; 

e si è pronti a fare croce -dominio con sessione condivisa.

+1

utente '$ .ajaxSetup' per aggiungere' withCredentials: true' a ogni richiesta – Xerri

+0

@Maksims "Utilizzo del dominio non funzionerà bene su localhost" - perché non funziona su localhost? Ho: api.localhost: 3000 e localhost: 3000 - non funziona? : \ – AmpT

+0

Perché per sicurezza del browser, il cookie non verrà inviato se il dominio corrente non corrisponde al dominio definito. Per gli ambienti di sviluppo e stage è sufficiente commentare la proprietà del dominio o impostarla su "localhost". – moka

2

Ti sei assicurato di avere i cookie impostati sul dominio di primo livello in modo che possano essere letti da tutti i sottodomini? Quindi è solo questione o persistere i dati della sessione in memoria, un db, come al solito. Non ho la mia macchina di sviluppo attiva e funzionante, ma sarà simile a questa nella tua 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) 
    } 
})); 
+1

Ho aggiunto il tuo suggerimento ma non ha fatto alcuna differenza. Ho provato "example.com", "* .example.com" e ".example.com". Ho aggiunto più codice nella mia domanda originale per descrivere il processo un po 'meglio. Penso che potrebbe essere un problema con il redirect ... – mattgi

+0

@mattgi Prova a rimuovere tutti i cookie nel tuo browser dopo aver cambiato il tuo codice. Questa risposta mi sembra buona. – InspiredJW

+0

@InspiredJW l'hanno fatto .. forse perché sto funzionando localmente? quando setto session.user = user e poi registro la sessione in console posso vederlo lì, ma nel momento in cui reindirizzo l'utente scompare .. Potrebbe infatti non essere correlato al "problema" del sottodominio che sto provando a risolve come sembra che la mia sessione non stia semplicemente lavorando su qualsiasi percorso (anche sulla stessa intestazione host). – mattgi

0

Nota: Se si utilizza il nuovo modulo cookie di sessione Express 4 e, il codice è simile

{ 
    secret: <session_secret> , 
    store: <session store> , 
    domain: '.domain.com', 
} 

Questo mi ha morso, ma l'API è cambiato.