无法访问socket.io中的快速会话

问题描述 投票:0回答:1

我正在开发一个使用socket.io 和express-session 包的项目。 现在的问题是我无法获取我已经使用登录或身份验证设置的会话对象。

下面是我的 server.ts 文件

import SocketService from "./services/socket";
const express = require("express");
const app = express();
const cors = require("cors");
const session = require("express-session");
const MongoStore = require("connect-mongo");
const cookieParser = require("cookie-parser"); // Import the cookie-parser package

app.use(express.json());
app.use(cookieParser());

//importing the dotenv package to use the environment variables
require("dotenv").config();
const port = process.env.NODE_ENV_PORT || 3000;

//importing the database connection
const conn = require("./db.ts");
const client = conn();

//defining cors options
const corsOptions = {
  origin: ["http://localhost:3000","http://localhost:5173"],
  methods: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"],
  credentials: true,
  optionsSuccessStatus: 200,
};

// setting up the session
const sessionMiddleware = session({
  name: "solace-session-id",
  secret: process.env.NODE_ENV_SESSION_SECRET,
  resave: true,
  saveUninitialized: true,
  store: MongoStore.create({ client: client,
    dbName: "solace",
    ttl: 7 * 24 * 60 * 60 * 1000,
    collectionName: "sessions"
  }),
  cookie: {
    maxAge: 1000 * 60 * 60 * 24 * 7,
    sameSite: false,
    secure: app.get("env") === "production",
    httpOnly: true,
  },
})

app.use(sessionMiddleware);

// just for checking if the server is running
app.get("/", (req : any, res: { send: (arg0: string) => void; }) => {
  console.log("session id",req.sessionID);
  console.log("session",req.session)
  res.send("Hello World!");
});

//defining the routes for the app
app.use("/api/auth", cors(corsOptions), require("./routes/auth"));

const server = app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

//socket service (Implementation is given below)
const socketService = new SocketService();

socketService.io.attach(server);

socketService.io.engine.use(sessionMiddleware);

socketService.initListener();

这里我在下面的文件中创建了一个socketService类

SocketService.ts

import { Redis } from "ioredis";
import { Server } from "socket.io";

declare module 'http'{
    interface IncomingMessage{
        session: any,
        sessionID: string,
        sessionStore: any
    }
}

//importing the environment variables
require("dotenv").config();

const pub = new Redis({
    host: process.env.NODE_ENV_REDIS_HOST,
    port: parseInt(process.env.NODE_ENV_REDIS_PORT as string),
    username: process.env.NODE_ENV_REDIS_USERNAME,
    password: process.env.NODE_ENV_REDIS_PASSWORD,
});
const sub = new Redis({
    host: process.env.NODE_ENV_REDIS_HOST,
    port: parseInt(process.env.NODE_ENV_REDIS_PORT as string),
    username: process.env.NODE_ENV_REDIS_USERNAME,
    password: process.env.NODE_ENV_REDIS_PASSWORD,
});

class SocketService {
    private _io: Server;

    constructor() {
        this._io = new Server({
            cors: {
                origin: "*", // Allow all origins for development
                allowedHeaders: ["*"],
                methods: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"],
                credentials: true,
                optionsSuccessStatus: 200,
            },
        });
        sub.subscribe("chat");
    }


    //setting listener for the socket
    public initListener() {
        console.log("Initializing socket listeners");

        this.io.on("connect", (socket) => {
            ***console.log("Session: ", socket.request.session);***

            socket.on("message", async ({ message, email }: { message: string, email: string }) => 
                await pub.publish("chat", JSON.stringify({ message, email }));
            });
            //on disconnect
            socket.on("disconnect", () => {
                console.log("User disconnected");
            });
        });

        //on message received
        sub.on("message", (channel, message) => {
            console.log("Message received from channel: ", channel);
            this.io.emit("message", JSON.parse(message));
        });
    }
}

export default SocketService;

当我连接到插座时

this.io.on("connect",...)
我尝试访问会话的方法 在这里,我可以获得如下会话:

Session :  Session {
   cookie: {
     path: '/',
     _expires: 2024-04-10T19:42:49.449Z,
     originalMaxAge: 604800000,
     httpOnly: true,
     sameSite: false,
     secure: false
   }
 }

但无法获取我在登录时设置的用户对象 虽然我能够在其他快速路线中访问相同的会话对象

我正在关注socket.io的文档

https://socket.io/how-to/use-with-express-session
我期望我应该获得用户对象而不仅仅是会话对象中的cookie。 我使用 mongodb 来存储会话,使用 redis 来进行实时聊天。 聊天和会话存储都运行良好。

我有一些解决方案,但它基于旧文档,所以我需要基于当前文档的解决方案

reactjs mongodb express socket.io
1个回答
0
投票

好吧,两天后我想通了: 问题主要是快速会话处理 您需要如下配置express-session:

const sessionMiddleware = session({
  name: "solace-session-id",
  secret: process.env.NODE_ENV_SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  store: MongoStore.create({ client: client,
    dbName: "dbname",
    ttl: 7 * 24 * 60 * 60 * 1000,
    collectionName: "sessions"
  }),
  cookie: {
    maxAge: 1000 * 60 * 60 * 24 * 7,
    sameSite: false, //false
    secure: app.get("env") === "production",
    httpOnly: true,
  },
})

如您所见,主要变化在于

resave : false
saveUninitialized:false

问题是它在每个请求上在 MongoDB 集合中创建新的会话对象,这导致 sessionID 与实际设置用户对象的 sessionID 不同

并且您还需要在客户端设置

socket.io-client
时包含withCredentials: true,如下所示:

const [socket, setSocket] = useState<Socket | undefined>(undefined);

// initialize socket client 
useEffect(()=> {
    const _socket = io('http://localhost:5400',
    {
        withCredentials: true
    });

    _socket.on('connect', () => {
        console.log('Socket connected!');
        console.log(_socket);
        setSocket(_socket);
    });

    return () => {
        _socket.disconnect();
        setSocket(undefined);
    }
},[]);

并且不要忘记在 socketserver 中包含 CORS 策略 作为参考,我在 socket.ts 中设置了 CORS,如下所示:

class SocketService {
private _io: Server;

constructor() {
    this._io = new Server({
        cors: {
            origin: ["http://localhost:3000","http://localhost:5173"], // Allow all origins for development
            allowedHeaders: ["*"],
            methods: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"],
            credentials: true,
            optionsSuccessStatus: 200,
        },
    });
    sub.subscribe("chat");

    // always remember to attach the server to the socket
    // and to initialize the listener
    // this.io.listen(5400);
}
// other code......
}

并且不要忘记在 CORS 中包含

methods : ["OPTIONS"]
,因为套接字会发送预检请求。

谢谢你:)

© www.soinside.com 2019 - 2024. All rights reserved.