You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中Socket.IO的JWT验证中间件未执行问题求助

Socket.IO JWT中间件不执行的解决方法

问题根源

你当前用MiddlewareConsumer绑定中间件的方式只适用于HTTP路由,WebSocket连接不会触发这类中间件,所以自定义的SocketJwtMiddleware完全没被执行。另外,SocketJwtMiddleware实现了NestMiddleware接口,这是HTTP中间件的标准,和WebSocket中间件的签名不匹配。

解决方案

下面提供两种符合NestJS规范的WebSocket认证方案:

方案一:使用WebSocket守卫(推荐)

创建一个守卫类处理JWT验证,这是NestJS官方推荐的WebSocket认证方式。

  1. 创建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('令牌无效');
    }
  }
}
  1. 在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原生写法的场景。

  1. 调整中间件类(无需实现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')); // 验证失败,终止连接并返回错误
    }
  }
}
  1. 在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);
    });
  }

  // ... 原有消息处理方法
}

额外注意事项

  1. 确保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 {}
  1. 修正CORS配置:原配置中的path不是CORS的合法选项,应使用origin指定允许的前端域名,避免生产环境使用*带来安全风险。

内容的提问来源于stack exchange,提问作者farshid.chegini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 03:10:42