Socket.IO和Express session不共享它们的会话

4
我将为您翻译以下内容:

我正在尝试连接express API和socket.IO服务器的会话。但是似乎两者都在单独存储它们的会话。socket.IO具有连接会话,而express服务器具有用户 qid 会话。我正在使用express ^4.17.1 和 socket.IO ^4.1.2。这是我的代码:

/server.js

const express = require("express");
const session = require("express-session");
const sharedSession = require("express-socket.io-session");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser("secret"));
const corsConfig = {
  origin: function (origin, callback) {
    if (!origin || whitelist.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
};

const server = require("http").createServer(app);
const io = require("socket.io")(server, { cors: corsConfig });

const whitelist = ["http://localhost:3000", "http://192.168.2.104:3000"];

const sessionMiddleware = session({
  secret: "keyboard cat",
  cookie: { maxAge: 60000 },
  name: "qid",
});
// register middleware in Express
app.use(sessionMiddleware);
// register middleware in Socket.IO
io.use((socket, next) => {
  sessionMiddleware(socket.request, {}, next);
  // sessionMiddleware(socket.request, socket.request.res, next); will not work with websocket-only
  // connections, as 'socket.request.res' will be undefined in that case
});

// TRIED, BUT SAME RESULT. . .
// io.use(sharedSession(sessionMiddleware, { autoSave: true }));

app.get("/", (req, res) => {
  req.session.qid = "sdfdsfsadgfas";
  req.session.save();
  console.log(
    "CONNECTIONS / QID (EXPRESS SERVER)",
    req.session.connections,
    req.session.qid
  );
  res.json({ success: true });
});

io.on("connection", (socket) => {
  const session = socket.request.session;
  // console.log(socket.request);
  if (!session.connections) session.connections = 0;
  session.connections++;
  session.save();
  socket.on("a", () => {
    session.reload((err) => {
      if (err) console.log("ERROR", err);

      console.log(
        "CONNECTIONS / QID (IO SERVER)",
        session.connections,
        session.qid
      );
    });
  });
});

const port = process.env.PORT || 5000;
server.listen(port, () => console.log("server listening on port " + port));

/client.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test</title>
  </head>
  <body></body>
  <script
    src="https://cdn.socket.io/3.1.3/socket.io.min.js"
    integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh"
    crossorigin="anonymous"
  ></script>
  <script>
    const socket = io("http://localhost:5000");
    fetch("http://localhost:5000/").then(() => socket.emit("a"));
  </script>
</html>

请帮我解决这个问题,提前致谢。


1
它们应该是这样的-Express是一个Web服务器,Socket.io是一个WebSocket服务器;它们的会话非常不同,在设置WebSocket连接时,Express仅充当一个通过中介而已。作为Web服务器,Express接收带有“升级此连接为WebSocket连接”的指令的HTTP GET请求,并通过将其移交给socket.io来遵循它,而不是执行任何操作。之后,Express就完成了:它不参与任何WebSocket通信,也不应知道有关socket会话的任何信息。 - Mike 'Pomax' Kamermans
我明白了,你知道如何合并会话吗? - plutolaser
1
那不是会话信息,那是“用户信息”,所以我强烈建议编写一个用户类来保存这样的信息。用户登录您的Web服务器后,您创建他们的用户对象,他们的浏览器请求WebSocket连接,您的Web服务器请求socket.io接管并使您的代码向其构建的套接字添加一个user属性,指向该用户对象。 - Mike 'Pomax' Kamermans
1
再次强调:Web服务器是建立任何连接的中介者,因此Web服务器决定某个人是否已正确进行身份验证。如果他们没有通过身份验证,则不允许WebSocket连接。如果他们通过了身份验证,则允许连接。WebSocket无需了解Web服务器的会话管理情况。 - Mike 'Pomax' Kamermans
明白了。谢谢你的回答!这真的帮助我理解了这些过程! - plutolaser
显示剩余4条评论
1个回答

1
您可以在连接时传递加密的会话ID,并在后端解密它...

前端

const socket = io("http://localhost:5000?session=sessionIdEncrypted");

后端

io.on("connection", socket => {
    const givenSessionId = socket.handshake.query.session
    // here you decrypt the session id and find it in the store
})

我正在使用httpOnly Cookies。我该如何从我的代码中访问它? - plutolaser
你可以先调用后端并请求会话ID,然后使用获取的sessionId连接socket.io... - BENARD Patrick
听起来不错,但如果用户可以获取会话ID而不是直接访问cookie,那么httpOnly属性的目的不就失去了吗?我将sessionId存储在httpOnly cookie中。抱歉,我是初学者,请告诉我如果我的观点不正确。 - plutolaser
1
这里不涉及到cookies的问题,你提供加密的会话ID,通过ID检索会话... 你有会话ID,所以你可以按照文档这里所说的去做,你在连接时获取会话,一旦检索到,你就可以在每个socket 'on message'中传递它。 - BENARD Patrick
这是否意味着不需要将express session socket中间件绑定到socket.io? - cdaiga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接