NestJS中Socket.IO的JWT验证中间件未执行问题求助
Socket.IO JWT中间件不执行的解决方法
问题根源
你当前用MiddlewareConsumer绑定中间件的方式只适用于HTTP路由,WebSocket连接不会触发这类中间件,所以自定义的SocketJwtMiddleware完全没被执行。另外,SocketJwtMiddleware实现了NestMiddleware接口,这是HTTP中间件的标准,和WebSocket中间件的签名不匹配。
解决方案
下面提供两种符合NestJS规范的WebSocket认证方案:
方案一:使用WebSocket守卫(推荐)
创建一个守卫类处理JWT验证,这是NestJS官方推荐的WebSocket认证方式。
- 创建
SocketJwtGuard
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Socket } from 'socket.io'; @Injectable() export class SocketJwtGuard implements CanActivate { constructor(private readonly jwtService: JwtService) {} canActivate(context: ExecutionContext): boolean { const client = context.switchToWs().getClient<Socket>(); const token = client.handshake.auth?.token; if (!token) { throw new UnauthorizedException('未提供令牌'); } try { const decoded = this.jwtService.verify(token, { secret: process.env.JWT_SECRET, }); // 将解析后的用户信息挂载到socket上 client['user'] = decoded; return true; } catch (error) { throw new UnauthorizedException('令牌无效'); } } }
- 在SocketGateway中使用守卫
将守卫添加到Gateway类上,对所有连接和消息生效:
import { UseGuards } from '@nestjs/common'; import { WebSocketGateway, WebSocketServer, OnModuleInit } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { SocketJwtGuard } from './socketJwt.guard'; @WebSocketGateway({ cors: { origin: '*', // 按需配置允许的前端域名,比如['http://localhost:3000'] methods: ['GET', 'POST'], }, }) @UseGuards(SocketJwtGuard) // 全局应用守卫 export class SocketGateway implements OnModuleInit { @WebSocketServer() server: Server; onModuleInit() { this.server.on('connection', (socket: any) => { console.log('connection', socket.id); console.log('当前用户:', socket.user); // 可以获取到解析后的用户信息 }); } @SubscribeMessage('message') handleEvent(@MessageBody() data: string, @ConnectedSocket() client: Socket): string { console.log('message', data); console.log('客户端ID:', client.id); return data; } }
方案二:使用Socket.IO原生中间件
直接给Socket.IO服务器添加原生中间件,适合习惯Socket.IO原生写法的场景。
- 调整中间件类(无需实现NestMiddleware)
import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Socket } from 'socket.io'; @Injectable() export class SocketJwtMiddleware { constructor(private readonly jwtService: JwtService) {} use(socket: Socket, next: (err?: Error) => void) { console.log('+++++++++++++++++'); const token = socket.handshake.auth?.token; try { if (token) { const decode = this.jwtService.verify(token, { secret: process.env.JWT_SECRET, }); socket['user'] = decode; } console.log('Request...'); next(); // 验证通过,继续连接 } catch (error) { next(new Error('Unauthorized')); // 验证失败,终止连接并返回错误 } } }
- 在Gateway中注册中间件
有两种方式:
- 方式一:通过Gateway配置注册(NestJS 9+支持)
import { WebSocketGateway, WebSocketServer, OnModuleInit } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { SocketJwtMiddleware } from './socketJwt.middleware'; @WebSocketGateway({ cors: { origin: '*', methods: ['GET', 'POST'], }, middleware: [SocketJwtMiddleware], // 直接配置中间件 }) export class SocketGateway implements OnModuleInit { @WebSocketServer() server: Server; onModuleInit() { this.server.on('connection', (socket: any) => { console.log('connection', socket.id); }); } // ... 原有消息处理方法 }
- 方式二:在onModuleInit中手动添加
import { Inject } from '@nestjs/common'; import { WebSocketGateway, WebSocketServer, OnModuleInit } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { SocketJwtMiddleware } from './socketJwt.middleware'; @WebSocketGateway({ cors: { origin: '*', methods: ['GET', 'POST'], }, }) export class SocketGateway implements OnModuleInit { @WebSocketServer() server: Server; constructor(@Inject(SocketJwtMiddleware) private readonly jwtMiddleware: SocketJwtMiddleware) {} onModuleInit() { // 添加Socket.IO中间件 this.server.use((socket: Socket, next) => this.jwtMiddleware.use(socket, next)); this.server.on('connection', (socket: any) => { console.log('connection', socket.id); }); } // ... 原有消息处理方法 }
额外注意事项
- 确保
JwtModule已在SocketModule中导入,否则JwtService无法注入:
import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { SocketGateway } from './socket.gateway'; import { SocketJwtGuard } from './socketJwt.guard'; // 或SocketJwtMiddleware @Module({ imports: [ JwtModule.register({ secret: process.env.JWT_SECRET, }), ], providers: [SocketGateway, SocketJwtGuard], // 注册守卫或中间件 }) export class SocketModule {}
- 修正CORS配置:原配置中的
path不是CORS的合法选项,应使用origin指定允许的前端域名,避免生产环境使用*带来安全风险。
内容的提问来源于stack exchange,提问作者farshid.chegini
相关产品推荐
相关产品推荐

