使用Express和Node,如何在子域/主机头之间维护会话

我有一个节点服务器响应请求,并根据主机头redirect用户。 用法是静态/主页站点位于www,每个用户都有自己的子域(即www.example.com和site.example.com)。 路由是根据site.js。

当用户没有login时,他们被redirect到login。

我发现当用户被redirect到他们的子域时,会话不被维护。 我想这是预期的,但我想知道是否有一种方法来维护两个子域相同的会话。

我希望如果他们login并返回到www.example.com,他们会看到一个不同的视图,其中包括一个链接注销/他们的仪表板,等我现在的解决方法,我想,只是创build会话在他们的子域名,如果他们确实返回到www它就好像他们没有login。

任何人之前处理过这个问题,或者有如何处理会话的答案?

我认为这个问题可能在users.js,因为它不是一个相对path,我redirect到'http://site.example.com'…

这里是相关的代码(用户查找是使用MongoDB完成的,因为它的工作正常,所以我把它放在了外面 – 调用这个服务的行是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 

为了在OSX本地testing它,我已经将www.example.com和site.example.com添加到我的主机文件中,以便在本地处理DNS查找。

首先为了让浏览器发出跨域请求,你需要在服务器端设置标题。 此解决scheme适用于正常请求以及AJAX。 在你的快速configurationfunction中:

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(); }); 

如果不需要跨域cookie交换会话,Access-Control-Allow-Origin可以设置为“*”。 要让cookie和会话共享跨域,您需要将特定的Access-Control-Allow-Origin设置为实际的请求所在的域,这就是为什么req.headers.origin是完美的。

使用域,它不会在本地主机上运行良好 – 所以请确保您在开发环境中禁用它,并启用生产。 它将启用顶部和子域的共享cookie。

这不是全部。 它自己的浏览器不会通过跨域请求发送cookie,而这必须被强制。 在jQuery中,您可以在$ .ajax()请求中添加额外的参数:

 xhrFields: { withCredentials: true } 

对于非jQuery,只需要XHR构造函数并设置此参数:

 xhr.withCredentials = true; 

而且您已准备好使用共享会话进行跨域。

你有没有确定你的cookies设置为顶级域名,以便所有子域名都可以读取? 那么这只是一个问题或坚持你的会议数据在内存,一个数据库,一切照旧。 我没有开发我的开发机器,但它会在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) } })); 

注意:如果使用Express 4和新的cookie会话模块,代码如下所示

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

这一点我,但API已经改变。