Socket.io 1.0 및 Express 4.x와 세션을 공유하려면 어떻게해야합니까? Redis Store를 사용하지만 중요하지 않다고 생각합니다. 쿠키를보고 세션을 가져 오기 위해 미들웨어를 사용해야한다는 것을 알고 있지만 방법을 모릅니다. 나는 수색했지만 어떤 일도 찾을 수 없었다
var RedisStore = connectRedis(expressSession);
var session = expressSession({
store: new RedisStore({
client: redisClient
}),
secret: mysecret,
saveUninitialized: true,
resave: true
});
app.use(session);
io.use(function(socket, next) {
var handshake = socket.handshake;
if (handshake.headers.cookie) {
var str = handshake.headers.cookie;
next();
} else {
next(new Error('Missing Cookies'));
}
});
답변
해결책은 놀랍도록 간단합니다. 잘 문서화되어 있지 않습니다. 다음과 같은 작은 어댑터를 사용하여 Express 세션 미들웨어를 Socket.IO 미들웨어로 사용할 수도 있습니다.
sio.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
다음은 Express 4.x, Socket.IO 1.x 및 Redis를 사용한 전체 예제입니다.
var express = require("express");
var Server = require("http").Server;
var session = require("express-session");
var RedisStore = require("connect-redis")(session);
var app = express();
var server = Server(app);
var sio = require("socket.io")(server);
var sessionMiddleware = session({
store: new RedisStore({}), // XXX redis server config
secret: "keyboard cat",
});
sio.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res || {}, next);
});
app.use(sessionMiddleware);
app.get("/", function(req, res){
req.session // Session object in a normal request
});
sio.sockets.on("connection", function(socket) {
socket.request.session // Now it's available from Socket.IO sockets too! Win!
});
server.listen(8080);
답변
불과 한 달 반 전에 나는 같은 문제를 다루었 고 그 후 GitHub에서 호스팅 되는 완전히 작동하는 데모 앱 과 함께이 주제에 대한 광범위한 블로그 게시물 을 작성했습니다 . 이 솔루션은 모든 것을 묶기 위해 express-session , cookie-parser 및 connect-redis 노드 모듈에 의존 합니다. 매우 유용한 REST 및 소켓 컨텍스트에서 세션에 액세스하고 수정할 수 있습니다.
두 가지 중요한 부분은 미들웨어 설정입니다.
app.use(cookieParser(config.sessionSecret));
app.use(session({
store: redisStore,
key: config.sessionCookieKey,
secret: config.sessionSecret,
resave: true,
saveUninitialized: true
}));
… 및 SocketIO 서버 설정 :
ioServer.use(function (socket, next) {
var parseCookie = cookieParser(config.sessionSecret);
var handshake = socket.request;
parseCookie(handshake, null, function (err, data) {
sessionService.get(handshake, function (err, session) {
if (err)
next(new Error(err.message));
if (!session)
next(new Error("Not authorized"));
handshake.session = session;
next();
});
});
});
그들은 세션에 대한 몇 가지 기본 작업을 수행 할 수 있도록 만든 간단한 sessionService 모듈과 함께 이동하며 해당 코드는 다음과 같습니다.
var config = require('../config');
var redisClient = null;
var redisStore = null;
var self = module.exports = {
initializeRedis: function (client, store) {
redisClient = client;
redisStore = store;
},
getSessionId: function (handshake) {
return handshake.signedCookies[config.sessionCookieKey];
},
get: function (handshake, callback) {
var sessionId = self.getSessionId(handshake);
self.getSessionBySessionID(sessionId, function (err, session) {
if (err) callback(err);
if (callback != undefined)
callback(null, session);
});
},
getSessionBySessionID: function (sessionId, callback) {
redisStore.load(sessionId, function (err, session) {
if (err) callback(err);
if (callback != undefined)
callback(null, session);
});
},
getUserName: function (handshake, callback) {
self.get(handshake, function (err, session) {
if (err) callback(err);
if (session)
callback(null, session.userName);
else
callback(null);
});
},
updateSession: function (session, callback) {
try {
session.reload(function () {
session.touch().save();
callback(null, session);
});
}
catch (err) {
callback(err);
}
},
setSessionProperty: function (session, propertyName, propertyValue, callback) {
session[propertyName] = propertyValue;
self.updateSession(session, callback);
}
};
이것보다 전체에 더 많은 코드가 있기 때문에 (모듈 초기화, 클라이언트 및 서버 측 모두에서 소켓 및 REST 호출로 작업) 여기에 모든 코드를 붙여 넣지는 않을 것이므로 GitHub에서 볼 수 있습니다. 원하는 것은 무엇이든 할 수 있습니다.
답변
문제에 대한 기성 솔루션입니다. 일반적으로 socket.io 끝에서 생성 된 세션은 express.js에서 생성 된 세션과 다른 sid를 갖습니다.
그 사실을 알기 전에 해결책을 찾기 위해 노력할 때 조금 이상한 것을 발견했습니다. express.js 인스턴스에서 생성 된 세션은 socket.io 끝에서 액세스 할 수 있었지만 반대의 경우에도 동일하지 않았습니다. 그리고 곧 나는 그 문제를 해결하기 위해 sid 관리를 통해 내 방식대로 일해야한다는 것을 알게되었습니다. 그러나 이미 이러한 문제를 해결하기 위해 작성된 패키지가 있습니다. 잘 문서화되어 있으며 작업을 완료합니다. 도움이되기를 바랍니다.
답변
Bradley Lederholz의 대답을 사용하여 이것이 내가 스스로 작동하도록 만든 방법입니다. 자세한 설명은 Bradley Lederholz의 답변을 참조하십시오.
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io');
var cookieParse = require('cookie-parser')();
var passport = require('passport');
var passportInit = passport.initialize();
var passportSession = passport.session();
var session = require('express-session');
var mongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
var sessionMiddleware = session({
secret: 'some secret',
key: 'express.sid',
resave: true,
httpOnly: true,
secure: true,
ephemeral: true,
saveUninitialized: true,
cookie: {},
store:new mongoStore({
mongooseConnection: mongoose.connection,
db: 'mydb'
});
});
app.use(sessionMiddleware);
io = io(server);
io.use(function(socket, next){
socket.client.request.originalUrl = socket.client.request.url;
cookieParse(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
socket.client.request.originalUrl = socket.client.request.url;
sessionMiddleware(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
passportInit(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
passportSession(socket.client.request, socket.client.request.res, next);
});
io.on('connection', function(socket){
...
});
...
server.listen(8000);
답변
나는 그것을 약간 해결했지만 완벽하지는 않습니다. 서명 된 쿠키 등을 지원하지 않습니다. Express-session 의 getcookie 기능을 사용했습니다. 수정 된 기능은 다음과 같습니다.
io.use(function(socket, next) {
var cookie = require("cookie");
var signature = require('cookie-signature');
var debug = function() {};
var deprecate = function() {};
function getcookie(req, name, secret) {
var header = req.headers.cookie;
var raw;
var val;
// read from cookie header
if (header) {
var cookies = cookie.parse(header);
raw = cookies[name];
if (raw) {
if (raw.substr(0, 2) === 's:') {
val = signature.unsign(raw.slice(2), secret);
if (val === false) {
debug('cookie signature invalid');
val = undefined;
}
} else {
debug('cookie unsigned')
}
}
}
// back-compat read from cookieParser() signedCookies data
if (!val && req.signedCookies) {
val = req.signedCookies[name];
if (val) {
deprecate('cookie should be available in req.headers.cookie');
}
}
// back-compat read from cookieParser() cookies data
if (!val && req.cookies) {
raw = req.cookies[name];
if (raw) {
if (raw.substr(0, 2) === 's:') {
val = signature.unsign(raw.slice(2), secret);
if (val) {
deprecate('cookie should be available in req.headers.cookie');
}
if (val === false) {
debug('cookie signature invalid');
val = undefined;
}
} else {
debug('cookie unsigned')
}
}
}
return val;
}
var handshake = socket.handshake;
if (handshake.headers.cookie) {
var req = {};
req.headers = {};
req.headers.cookie = handshake.headers.cookie;
var sessionId = getcookie(req, "connect.sid", mysecret);
console.log(sessionId);
myStore.get(sessionId, function(err, sess) {
console.log(err);
console.log(sess);
if (!sess) {
next(new Error("No session"));
} else {
console.log(sess);
socket.session = sess;
next();
}
});
} else {
next(new Error("Not even a cookie found"));
}
});
// Session backend config
var RedisStore = connectRedis(expressSession);
var myStore = new RedisStore({
client: redisClient
});
var session = expressSession({
store: myStore,
secret: mysecret,
saveUninitialized: true,
resave: true
});
app.use(session);
답변
이제 원래 수락 된 답변이 저에게도 효과가 없습니다. @ Rahil051과 마찬가지로 express-socket.io-session 모듈을 사용했으며 여전히 작동합니다. 이 모듈은 쿠키 파서를 사용하여 익스프레스 세션 미들웨어에 들어가기 전에 세션 ID를 구문 분석합니다. @pootzko, @Mustafa 및 @Kosar의 답변에 대한 실미라고 생각합니다.
다음 모듈을 사용하고 있습니다.
"dependencies":
{
"debug": "^2.6.1",
"express": "^4.14.1",
"express-session": "^1.15.1",
"express-socket.io-session": "^1.3.2
"socket.io": "^1.7.3"
}
socket.handshake의 데이터를 확인하십시오.
const debug = require('debug')('ws');
const sharedsession = require('express-socket.io-session');
module.exports = (server, session) => {
const io = require('socket.io').listen(server);
let connections = [];
io.use(sharedsession(session, {
autoSave: true,
}));
io.use(function (socket, next) {
debug('check handshake %s', JSON.stringify(socket.handshake, null, 2));
debug('check headers %s', JSON.stringify(socket.request.headers));
debug('check socket.id %s', JSON.stringify(socket.id));
next();
});
io.sockets.on('connection', (socket) => {
connections.push(socket);
});
};