2012-01-30 6 views
11

Mam serwer z pojedynczym węzłem, który odpowiada na żądania i przekierowuje użytkownika na podstawie nagłówków hosta. Jest tak, że strona statyczna/główna znajduje się na stronie www, a każdy użytkownik ma swoją własną domenę podrzędną (np. Www.example.com i site.example.com). Trasowanie odbywa się zgodnie z witryną.js.Używanie Express i Node, jak utrzymać sesję między subdomenami/hostheaders

Gdy użytkownik nie jest zalogowany, zostaje przekierowany do logowania.

Odkrywam, że sesja nie jest utrzymywana, gdy użytkownik jest przekierowywany do swojej poddomeny. Sądzę, że to jest oczekiwane, ale zastanawiam się, czy istnieje sposób na utrzymanie tej samej sesji w obu subdomenach.

Miałem nadzieję, że po zalogowaniu i powrocie na stronę www.example.com zobaczą inny widok zawierający link do wylogowania/ich pulpitów itp. Moje obejście w tym momencie, myślę, to po prostu utworzyć sesję na poddomenie i jeśli powrócą na stronę www, będzie po prostu tak, jakby nie byli zalogowani.

Ktoś poradził sobie z tym wcześniej lub ma odpowiedzi na temat obchodzenia się z sesjami w ten sposób?

Myślę, że problem może być w users.js gdzie przekierować do „http://site.example.com” jak jej nie względnej ścieżki ...

Oto odpowiedni kod (użytkownik wyszukiwanie odbywa się za pomocą MongoDB i zostawiłem go w jego pracy w porządku - linię, która wywołuje usługa ta jest 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     

przetestować go lokalnie na OSX, dodałem www.example.com i site.example.com w moim pliku hosts tak, że zapytania DNS uzyskać miejscowego.

Odpowiedz

23

Po pierwsze, aby umożliwić przeglądanie żądań między domenami, należy ustawić nagłówki po stronie serwera. To rozwiązanie działa zarówno w przypadku zwykłego żądania, jak i AJAX. W wyraźnej funkcji configure:

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 może być ustawiony na '*', jeśli nie wymiana ciasteczka cross-domain dla sesji potrzebne. Aby pliki cookie i sesja były współdzielone między domenami, musisz ustawić konkretną domenę Access-Control-Allow-Origin na rzeczywistą domenę, z której pochodzi żądanie, dlatego nazwa req.headers.origin - jest do tego idealna.

Używanie domeny nie będzie działało dobrze na localhost - więc upewnij się, że wyłączyłeś ją w środowisku programistycznym i włączyłeś ją podczas produkcji. Umożliwi to udostępnianie plików cookie w najwyższych i niższych domenach.

To nie wszystko. Przeglądarki same nie będą wysyłać plików cookie na żądania między domenami, a to musi być wymuszone. W jQuery można dodać dodatkowy parametr w $ .ajax() wniosek:

xhrFields: { withCredentials: true } 

Za niedopełnienie jQuery, po prostu konstruktora XHR i ustawić ten parametr:

xhr.withCredentials = true; 

i jesteś gotowy, aby zrobić krzyż -domain z udostępnioną sesją.

+1

użytkownik '$ .ajaxSetup', aby dodać' withCredentials: true' do każdego żądania – Xerri

+0

@Maksims "Korzystanie z domeny nie będzie działać dobrze na localhost" - dlaczego nie działa na localhost? Mam: api.localhost: 3000 i localhost: 3000 - nie działa? : \ – AmpT

+0

Ponieważ ze względu na bezpieczeństwo przeglądarki plik cookie nie zostanie wysłany, jeśli bieżąca domena nie jest zgodna ze zdefiniowaną domeną. W przypadku środowisk programistycznych i scenicznych można po prostu skomentować własność domeny lub ustawić ją na "localhost". – moka

2

Czy upewniłeś się, że Twoje pliki cookie są ustawione na domenę najwyższego poziomu, aby można było je odczytać przez wszystkie subdomeny? Wtedy to tylko kwestia lub utrwalenie danych sesji w pamięci, db, jak zwykle. Nie mam uruchomionej mojej maszyny, ale będzie to coś takiego w twojej 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

Dodałem w Twojej sugestii, ale nie miało to żadnej różnicy. Próbowałem "example.com", "* .example.com" i ".example.com". Dodałem więcej kodu do mojego oryginalnego pytania, aby nieco lepiej opisać proces. Myślę, że może to być problem z przekierowaniem ... – mattgi

+0

@mattgi Spróbuj usunąć wszystkie pliki cookie w przeglądarce po zmianie kodu. Ta odpowiedź wydaje mi się dobra. – InspiredJW

+0

@InspiredJW zrobił to .. może dlatego, że jestem uruchomiony lokalnie? kiedy ustawiam session.user = user, a potem loguję sesję na konsolę, mogę ją tam zobaczyć, ale w momencie, gdy przekierowuję użytkownika, znika. Może to być w rzeczywistości niezwiązane z subdomeną "problem" próbuję rozwiązać, ponieważ wygląda na to, że moja sesja nie działa po prostu na żadnych trasach (nawet na tym samym nagłówku hosta). – mattgi

0

Uwaga: W przypadku korzystania Express 4 oraz nowy moduł cookie-sesyjnego, kod wygląda

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

To mnie ugryzł, ale API nie zmieniło.

Powiązane problemy