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

Nestjs中如何让JwtStrategy的validate方法获取WebSocket请求上下文

实现方案

默认的AuthGuard('jwt')和JwtStrategy仅适配HTTP请求场景,要支持WebSocket场景下获取上下文、挂载用户payload,可按以下步骤改造:


步骤1:重写JwtAuthGuard适配双协议

重写守卫的getRequest方法,让其同时支持识别HTTP和WebSocket上下文,并且适配WebSocket专属的异常类型:

import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { WsException } from '@nestjs/websockets';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  // 适配不同上下文的请求对象提取逻辑
  getRequest(context: ExecutionContext) {
    // HTTP场景直接返回原生请求
    if (context.getType() === 'http') {
      return context.switchToHttp().getRequest();
    }
    // WebSocket场景返回握手信息对象,Passport会将其识别为请求载体
    if (context.getType() === 'ws') {
      return context.switchToWs().getClient().handshake;
    }
    throw new Error('不支持的上下文类型');
  }

  // 适配WebSocket场景的验证错误抛出逻辑
  handleRequest(err, user, info) {
    if (err || !user) {
      throw err || new WsException('身份验证失败');
    }
    return user;
  }
}

步骤2:改造JwtStrategy支持上下文获取

开启passReqToCallback配置让validate方法可以拿到上下文对象,同时自定义token提取逻辑适配WebSocket场景:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private authConfigService: AuthConfigService) {
    super({
      // 自定义token提取规则,同时适配HTTP和WebSocket
      jwtFromRequest: (request) => {
        // HTTP场景从Authorization头提取Bearer token
        if (request.headers?.authorization) {
          return ExtractJwt.fromAuthHeaderAsBearerToken()(request);
        }
        // WebSocket场景从握手请求的query参数提取token(也可根据前端传参方式调整为header取值)
        if (request.query?.token) {
          return request.query.token;
        }
        return null;
      },
      ignoreExpiration: false,
      secretOrKey: authConfigService.JWT_SECRET,
      // 开启该配置后,validate方法第一个参数会传入前面提取的请求上下文对象
      passReqToCallback: true,
    });
  }

  async validate(request: any, payload: any) {
    // WebSocket场景下可以将用户payload挂载到client实例,方便后续业务逻辑访问
    if (request.headers?.upgrade === 'websocket') {
      const wsClient = request.socket;
      wsClient.user = payload;
      // 也可根据需求挂载到后续消息体等其他对象上
    }
    return payload;
  }
}

步骤3:网关中使用&获取用户信息

在WebSocket网关直接用@UseGuards(JwtAuthGuard)装饰即可,后续业务逻辑中可以直接拿到挂载的用户信息:

@WebSocketGateway()
export class WsGateway {
  @UseGuards(JwtAuthGuard)
  @SubscribeMessage('testEvent')
  handleTestEvent(@Context() ctx: ExecutionContext) {
    const client = ctx.switchToWs().getClient();
    // 直接获取验证通过的用户信息
    const currentUser = client.user;
    // 也可以从handshake对象拿到Passport自动挂载的user属性
    const currentUser2 = client.handshake.user;
    return { event: 'testRes', data: '操作成功' };
  }
}

注意事项

  • 前端建立WebSocket连接时,需要将token放在握手请求的query参数或者请求头中(部分浏览器对WebSocket自定义header有限制,用query参数兼容性更好)
  • 如果不需要兼容HTTP场景,可以删掉策略中HTTP相关的token提取逻辑,仅保留WebSocket适配逻辑即可

内容的提问来源于stack exchange,提问作者Vahid Najafi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 00:15:08