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

NestJS中JwtAuthGuard验证失败却仍执行控制器方法问题

NestJS JwtAuthGuard验证失败但未阻止请求执行的排查思路

问题背景

接手的NestJS项目中配置了JwtAuthGuard用于校验JWT,从日志可见Guard已捕获JWT过期错误并抛出UnauthorizedException,但控制器方法仍能执行,且JwtRoleGuard输出了“用户权限验证通过”的日志,HTTP响应返回401但请求流程未被正确终止。

涉及代码

JwtAuthGuard实现

import {
  ExecutionContext,
  Injectable,
  UnauthorizedException,
  Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from './decorators/public.decorator';

@Injectable()
/**
 * An API guard used to indicate if the decorated API requires authenticaiton.  If the API's class (or method) is decorated with @Public, then authentication is not required.
 */
export class JwtAuthGuard extends AuthGuard('jwt') {

  private readonly logger = new Logger(JwtAuthGuard.name);

  constructor(private reflector: Reflector) {
    super();
  } 
  
  // returns true if the api is @Public.  Otherwise, the api will require a valid token as per the Passport strategy jwtauth.stratagy
  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    
    if (isPublic) {
      return true;
    } else {
      return super.canActivate(context);
    }
  } 
  
  handleRequest(err, user, info) {
    if (err || !user) {
      this.logger.error(`JWT is not Valid.  Err: ${err}. - User ${user}. - Info. ${info}`);
      throw err || new UnauthorizedException();
    }
    return user;
  }
}

控制器配置

@UseGuards(JwtRoleGuard)
@ApiTags("complaint")
@Controller({ path: 'complaint', version: '1'})
export class ComplaintController {
  constructor(private readonly complaintService: ComplaintService) {}

  @Get(':id')
  @Roles(Role.COS_OFFICER)
  findOne(@Param('id') id: string) {
    return this.complaintService.findOne(id);
  }

  @Patch(':id')
  @Roles(Role.COS_OFFICER)
  update(@Param('id') id: string, @Body() updateComplaintDto: UpdateComplaintDto) {
    return this.complaintService.update(id, updateComplaintDto);
  }
}

日志输出

2023-10-02 17:25:28 [Backend - c1c7ed] error    2023-10-03 12:25:28.331 [JwtAuthGuard]  JWT is not Valid.  Err: null. - User false. - Info. TokenExpiredError: jwt expired - { stack: [ null ] }
2023-10-02 17:25:28 [Backend - c1c7ed] info     2023-10-03 12:25:28.335 [HTTP]  PATCH /v1/hwcr-complaint/a5d359d1-1105-4b8e-b599-c66f3c948a56 401 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.81 - {}
2023-10-02 17:25:28 [Backend - c1c7ed] debug    2023-10-03 12:25:28.397 [JwtRoleGuard]  Guarded Roles: COS Officer - {}
2023-10-02 17:25:28 [Backend - c1c7ed] debug    2023-10-03 12:25:28.397 [JwtRoleGuard]  User authorization verified - {}

排查思路

1. 确认Guard的注册与执行顺序

  • 检查JwtAuthGuard的注册方式:如果是通过APP_GUARD令牌全局注册,全局Guard会先于控制器上的JwtRoleGuard执行。日志显示JwtAuthGuard抛出异常后JwtRoleGuard仍在执行,说明异常未中断请求流程,可能是JwtAuthGuard的异常被错误捕获,或是JwtRoleGuard未处理前置验证结果。
  • 核实JwtRoleGuard是否依赖JwtAuthGuard的验证结果:比如是否从request.user获取用户信息,如果没有判断request.user是否存在就直接通过验证,会导致JWT无效时仍能通过角色校验。

2. 检查JwtRoleGuard的核心逻辑

重点查看JwtRoleGuard的canActivate方法:

  • 是否存在if (!request.user) throw new UnauthorizedException()的判断?如果缺失,即使JwtAuthGuard抛出异常,JwtRoleGuard可能跳过用户有效性检查直接通过。
  • 是否错误使用try/catch捕获异常后返回true?比如捕获异常后未重新抛出,反而返回true,导致请求继续执行。

3. 验证JwtAuthGuard的异常抛出逻辑

  • 在handleRequest方法中增加日志,打印user的具体类型和值,确认Passport策略返回的user是否符合预期(比如是否为false或null)。
  • 确认super.canActivate(context)的异步处理:super.canActivate返回Promise<boolean>,如果未用async/await处理异步逻辑,可能导致异常未及时抛出,后续Guard继续执行。

4. 排查全局异常过滤器或拦截器

  • 检查是否存在自定义全局异常过滤器:如果过滤器错误捕获UnauthorizedException并修改响应,但未终止请求流程,会导致后续Guard继续执行。
  • 查看是否有拦截器在Guard之后执行:某些拦截器可能错误恢复请求流程,导致控制器方法执行。

5. 确认控制器方法是否真的执行

  • 在控制器的update和findOne方法中添加日志(如logger.log('update method triggered')),验证方法是否实际执行。日志中的HTTP 401可能是异常过滤器返回的,而控制器方法并未执行,需区分这两种情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:51:01