我有一个单节点服务器,该服务器响应请求并根据主机头重定向用户。用法是静态/主站点位于www,每个用户都有自己的子域(即www.example.com和site.example.com)。路由按照site.js。
当用户未登录时,他们将被重定向到登录名。
我发现当用户重定向到其子域时,无法维护该会话。我想这是预料之中的,但我想知道是否有一种方法可以在两个子域之间维持相同的会话。
我希望如果他们登录并返回到www.example.com,他们将看到一个不同的视图,其中包括注销链接/仪表板等。我想,目前的解决方法是创建子域中的会话,如果他们确实返回了www,就好像他们没有登录一样。
有人以前处理过这个问题,或者对如何以这种方式处理会话有答案?
我认为问题可能出在users.js中,我将其重定向到“ 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上进行本地测试,我在主机文件中添加了www.example.com和site.example.com,以便在本地处理DNS查找。
首先,要允许浏览器发出跨域请求,您需要在服务器端设置标头。该解决方案适用于普通请求以及AJAX。在您的快速配置功能中:
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的原因-非常适合。
使用domain不能在localhost上正常工作-因此请确保在开发环境中将其禁用,并在生产环境中启用。它将启用跨顶级域和子域的共享cookie。
这还不是全部。它本身的浏览器不会通过跨域请求发送cookie,因此必须强制这样做。在jQuery中,您可以在$ .ajax()请求中添加额外的参数:
xhrFields: { withCredentials: true }
对于非jQuery,只需具有XHR构造函数并设置以下参数:
xhr.withCredentials = true;
您就可以使用共享会话进行跨域了。