Express.js,如何将jwt cookie传递给Socket.io



我有一个登录路由,它最终创建了一个名为access_token的jwt cookie。登录后,客户端将收到此cookie,并在每次请求时发送。然而,我没有找到将这个cookie传递给Socket.io.的方法

服务器端登录路径:

const login = async (req, res) => {
const {email, password} = req.body
const user = await UserModel.findOne({email})
const isMatch = await user.checkPassword(password)
if (isMatch) {
const userToken = JwtService.createToken(user.id)
return res.cookie("access_token", userToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production"
}).status(200).json({user:user.toJSON(),message: 'login success'})
}
}

插座:

this.io = new socketio.Server(expressServer, {cors: {origin: 'http://localhost:3000'}})
this.io.use((socket,next)=>{
console.log(socket.handshake.headers.cookie); // undefiend
next()
})

客户:

this.socket = socketIOClient(process.env.SOCKET_BASE_URL, {auth: {userId}});

服务器:

import express, {RequestHandler} from 'express';
import http from 'http'
import cookieParser from "cookie-parser"
import cors from 'cors';
import {router} from '@router';
import dotenv from 'dotenv'
import mongoose from 'mongoose';
import {SocketService} from "@services";

const expressApp = express();

const port = process.env.PORT || 3001;
dotenv.config()

expressApp.use(cors({
origin: true,
credentials: true
}));
expressApp.use(express.json() as RequestHandler);
expressApp.use(cookieParser());
expressApp.use('/', router)

const httpServer = http.createServer(expressApp);
new SocketService(httpServer)

httpServer.listen(port, async () => {
console.log(`server is listening on ${port}`);
try {
await mongoose.connect('mongodb://guess-it-mongo-dev:27017/guess-it', {connectTimeoutMS: 1000});
console.log('connected to mongo server')
} catch (e) {
console.log(e);
}
});

1。解决方案

假设您只有一个cookie,即jwt,您可以使用socket参数来获取它,如下所示:

const token = socket.handshake.headers.cookie.split("=")[1];

如果你有很多cookie,你需要使用一些cookie解析器,并给它socket.handshake.headers.cookie来解析它,例如:

function getCookie(cName) {
const name = cName + "=";
const cDecoded = decodeURIComponent(socket.handshake.headers.cookie);
const cArr = cDecoded.split(';');
let res;
cArr.forEach(val => {
if (val.indexOf(name) === 0) res = val.substring(name.length);
})
return res;
}
const token = getCookie("jwt"); // if your token is called jwt.

2.故障排除

如果给定的解决方案不适合你,请确保你以这种方式设置你的应用程序和套接字,将它们作为一个服务器(可以随意更改端口(:

const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
server.listen(9000, () => {
console.log("server runnig on port " + 9000);
});

客户端应该像这样连接(使用与服务器相同的端口(:

import { io } from "socket.io-client";
io("http://localhost:9000/", {
transports: ["websocket"],
});

3.一个用例

例如,在代码中下面,我用中间件验证每个连接:

io.use((socket, next) => {
const token = socket.handshake.headers.cookie.split("=")[1];
if (token) {
jwt.verify(token, process.env.SECRET, (err, decodedToken) => {
if (err) {
next(new Error("invalid"));
} else {
User.findById(decodedToken.id, function (err, user) {
if (err) {
next(new Error("invalid"));
} else {
next();
}
});
}
});
} else {
next(new Error("invalid"));
}
});
//if authentication is ok, the code below will get executed 
io.on("connection", (socket) => {
// do things
})

最新更新