Использование Express и Node, как поддерживать сеанс между поддоменами/хост-узлами
У меня есть один сервер node, который отвечает на запросы и перенаправляет пользователя на основе заголовков хостов. Использование заключается в том, что статический/домашний сайт живет на www, и каждый пользователь имеет свой собственный домен (например, www.example.com и site.example.com). Маршрутизация выполняется по адресу site.js.
Когда пользователь не входит в систему, он перенаправляется на вход.
Я обнаруживаю, что сеанс не поддерживается, когда пользователь перенаправляется в свой дополнительный домен. Я предполагаю, что это ожидается, но мне интересно, есть ли способ поддерживать один и тот же сеанс в обоих поддоменах.
Я надеялся, что, если они войдут в систему и вернутся на сайт www.example.com, они увидели бы другое представление, которое включало бы ссылку на выход/свою панель инструментов и т.д. Мое обходное решение в данный момент, я думаю, просто создать сеанс на своем поддомене, и если они вернутся на www, это будет просто так, как будто они не вошли в систему.
Кто-нибудь имел дело с этим раньше или имеет ответы на вопросы о том, как обрабатывать сеансы таким образом?
Я думаю, что проблема может быть в users.js, где я перенаправляюсь на "http://site.example.com", поскольку это не относительный путь...
Вот соответствующий код (пользовательский поиск выполняется с помощью MongoDB, и я оставил его в качестве рабочего штрафа - строка, вызывающая эту услугу, является user.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 в мой файл hosts, чтобы запросы DNS обрабатывались локально.
Ответы
Ответ 1
Прежде всего, чтобы браузер выполнял кросс-доменные запросы, вам нужно установить заголовки на стороне сервера. Это решение работает как для обычного запроса, так и для AJAX.
В вашей функции экспресс-конфигурации:
Экспресс 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 может быть установлен в '*', если не требуется обмен файлами между доменами для сеансов.
Чтобы иметь общий доступ к файлам cookie и сеансам, вам необходимо установить конкретный Access-Control-Allow-Origin на фактический домен, откуда сделан запрос, поэтому req.headers.origin - идеально подходит для этого.
Используя домен, он не будет работать хорошо на localhost - поэтому убедитесь, что вы отключили его в среде разработки и включили в производство. Это позволит использовать общие файлы cookie в верхнем и дополнительном доменах.
Это еще не все.
Браузеры сами не будут отправлять файлы cookie через запросы перекрестных доменов, и это должно быть принудительно.
В jQuery вы можете добавить дополнительный параметр в запрос $.ajax():
xhrFields: { withCredentials: true }
Для не jQuery просто создайте конструктор XHR и установите этот параметр:
xhr.withCredentials = true;
И вы готовы выполнять междоменное соединение с общим сеансом.
Ответ 2
Вы убедились, что ваши файлы cookie настроены на домен верхнего уровня, чтобы его можно было читать по всем поддоменам? Тогда это просто вопрос или сохранение ваших данных сеанса в памяти, db, как обычно. У меня нет моей машины dev и работает, но это будет что-то вроде этого в 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)
}
}));
Ответ 3
Примечание. Если вы используете Express 4 и новый модуль cookie-сессии, код выглядит как
{
secret: <session_secret> ,
store: <session store> ,
domain: '.domain.com',
}
Это немного меня, но API изменился.