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

NestJS passport-jwt携带Bearer Token访问路由始终抛出Unauthorized

NestJS + passport-jwt 受保护路由返回401、validate方法不触发问题修复

问题核心原因

JwtStrategy.validate方法未执行、路由直接返回Unauthorized的根本原因是模块配置缺失:

  • AuthModule未导入@nestjs/passport提供的PassportModule,导致JWT策略根本没有注册到Passport执行流中,守卫匹配不到校验逻辑时会直接返回401,不会进入自定义校验方法
  • 受保护路由所在的业务模块(你的UserController所属的UserModule)未导入AuthModule,无法访问AuthModule下注册的JWT策略提供者

其余代码逻辑(令牌签发、密钥配置、Token提取规则、Guard写法)均无问题。

修复步骤

1. 补全AuthModule配置

修改auth.module.ts,导入Passport模块并导出相关提供者供其他模块使用:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './strategy';

@Module({
  imports: [
    // 注册Passport模块,指定默认策略为jwt
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.register({})
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  // 导出策略和Passport模块,其他模块导入AuthModule后即可使用JWT守卫
  exports: [JwtStrategy, PassportModule]
})
export class AuthModule {}

2. 业务模块导入AuthModule

找到UserController所属的user.module.ts,在imports数组中引入AuthModule:

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { AuthModule } from 'src/auth/auth.module';
// 保留你原有其他导入配置

@Module({
  imports: [AuthModule], // 加入AuthModule导入
  controllers: [UserController],
  // 保留你原有providers等配置
})
export class UserModule {}

(可选优化)统一JWT配置减少重复代码

你当前签发令牌时每次手动传入secret和过期时间,可以直接在JwtModule注册时统一配置,避免多端配置不一致:
修改auth.module.ts中的JwtModule注册逻辑为异步注册,从ConfigService读取配置:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './strategy';

@Module({
  imports: [
    ConfigModule,
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get('JWT_SECRET'),
        signOptions: { expiresIn: '10m' }
      })
    })
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  exports: [JwtStrategy, PassportModule]
})
export class AuthModule {}

简化后的signToken方法无需重复传配置:

private async signToken(userId: number, email: string): Promise<{ access_token: string }> {
  const payLoad = {
    sub: userId,
    email,
  };
  const token = await this.jwt.sign(payLoad);
  return { access_token: token };
}

验证

重启服务后重新发起请求:

  • 携带合法Bearer Token请求/users/me时,控制台会打印validate方法中的payload日志,接口正常返回Hello JWT
  • 未携带Token、Token非法/过期时才会返回401响应

若配置修改后仍返回401,检查Postman请求头中Authorization字段格式:确保Bearer和token之间只有一个空格,token复制完整无多余换行、空格字符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:45:47