如何在Socket.IO中使用自定义authorize授权中间件?
在Socket.IO中使用自定义授权中间件的正确方式
问题根源
你当前的写法有两个核心问题:
- Socket.IO的
use()方法仅接受单个中间件函数作为参数,你传入了两个参数(authorize(Role.Admin)和日志函数),导致第二个函数完全不会被执行。 - Express和Socket.IO的中间件参数结构不同:Express是
(req, res, next),Socket.IO是(socket, next),直接复用Express的authorize中间件会因参数不匹配失效。
解决步骤
1. 适配授权中间件到Socket.IO
需要修改或封装原有的authorize中间件,使其兼容Socket.IO的参数结构,并从Socket.IO的握手上下文获取授权信息:
假设原Express授权中间件逻辑如下:
function authorize(requiredRole) { return (req, res, next) => { const user = extractUserFromRequest(req); // 从req提取用户信息的自定义逻辑 if (user && user.role === requiredRole) { next(); } else { res.status(403).send("无权限"); } }; }
适配为Socket.IO版本:
function authorizeSocket(requiredRole) { return (socket, next) => { // 从握手请求头中获取授权信息(比如Bearer token) const authHeader = socket.handshake.headers.authorization; const token = authHeader?.split(" ")[1]; // 复用原有的用户验证逻辑 const user = verifyTokenAndGetUser(token); // 替换为你的token验证函数 if (user && user.role === requiredRole) { // 将用户信息挂载到socket上,后续事件处理可直接使用 socket.user = user; next(); // 授权通过,执行下一个中间件/连接逻辑 } else { // 授权失败,传递错误,Socket.IO会自动拒绝连接 next(new Error("无权限访问")); } }; }
2. 正确注册Socket.IO中间件
Socket.IO的use()每次只能注册一个中间件,多个逻辑需要分开调用或链式处理:
方式一:分开注册多个中间件
// 先注册授权中间件 io.use(authorizeSocket(Role.Admin)); // 再注册日志中间件(必须调用next()) io.use((socket, next) => { console.log("here"); next(); // 不调用next会阻塞后续逻辑执行 });
方式二:单个中间件内链式处理
如果需要授权通过后立即执行日志逻辑,可以合并为一个中间件:
io.use((socket, next) => { authorizeSocket(Role.Admin)(socket, (err) => { if (err) return next(err); // 授权失败,直接传递错误 console.log("here"); next(); // 继续执行后续逻辑 }); });
关键注意事项
- Socket.IO中间件必须调用
next()才能推进流程,授权失败时调用next(new Error("错误信息")),Socket.IO会自动断开连接并触发客户端的connect_error事件。 - 授权信息通常从
socket.handshake.headers获取,这是Socket.IO建立连接时携带的HTTP请求头。 - 不要直接复用Express中间件,必须适配Socket.IO的参数结构。
内容的提问来源于stack exchange,提问作者Sara Ree
相关产品推荐
相关产品推荐

