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
相关产品推荐
相关产品推荐

