Express.js,如何将jwt cookie传给Socket.io?
Express.js, how to pass jwt cookie to 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。一个用例
比如在代码中
下面,我正在使用 middleware 验证每个连接:
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
})
我有一个登录路由,最终会创建一个名为 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。一个用例
比如在代码中 下面,我正在使用 middleware 验证每个连接:
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
})