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

Nest中使用passport-jwt的secretOrKeyProvider返回401,validate未触发

NestJS 结合 Passport-JWT 与 Firebase 认证出现 401 错误及 Validate 方法未调用的解决办法

我是NestJS新手,想要使用passport-jwt、@nestjs/passport和Firebase构建应用的认证部分,但一直收到HTTP 401响应,且发现FirebaseStrategy中的validate方法没有被调用,按道理每次secretOrKeyProvider验证HTTP头中的JWT后都应该调用它,这该如何解决?

我的策略代码:

import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { getAuth } from 'firebase-admin/auth';

@Injectable()
export class FirebaseStrategy extends PassportStrategy(Strategy, 'firebase') {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKeyProvider: async (request, rawJwtToken, done) => {
        try {
          const decodedToken = await getAuth().verifyIdToken(rawJwtToken);
          done(null, decodedToken);
        } catch (error) {
          done(error);
        }
      },
    });
  }

  async validate(payload: any) {
    console.log('validate');
    return payload;
  }
}

我的守卫代码:

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class FirebaseAuthGuard extends AuthGuard('firebase') {}

我的auth.module.ts代码:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { FirebaseStrategy } from './firebase.stragety';
import { AuthController } from './auth.controller';

@Module({
  controllers: [AuthController],
  imports: [UsersModule, PassportModule, JwtModule.register({})],
  providers: [AuthService, FirebaseStrategy],
  exports: [AuthService],
})
export class AuthModule {}

我的控制器代码:

import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { FirebaseAuthGuard } from './firebase.guard';

@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @UseGuards(FirebaseAuthGuard)
  @Get('login')
  async logIn(@Request() req) {
    return 'login';
  }
}

问题原因分析

核心问题是错误使用了secretOrKeyProvider:passport-jwt的secretOrKeyProvider设计初衷是提供用于验证JWT签名的密钥/公钥,而非直接完成Token的全流程验证。你在该方法中调用Firebase的verifyIdToken并返回解码后的Token,会导致passport-jwt尝试用这个返回值去校验JWT签名,逻辑完全错误,最终验证失败返回401,validate方法根本不会被触发。

另外,auth.module.ts中存在拼写错误:导入FirebaseStrategy时路径写成了./firebase.stragety(stragety应为strategy),这会导致Strategy无法被正确注册,也是引发401的潜在原因。

解决方案

  1. 重构Strategy的验证逻辑
    移除secretOrKeyProvider,将Firebase的Token验证逻辑移到validate方法中,这才是符合passport-jwt流程的正确做法:

    import { ExtractJwt, Strategy } from 'passport-jwt';
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { getAuth } from 'firebase-admin/auth';
    
    @Injectable()
    export class FirebaseStrategy extends PassportStrategy(Strategy, 'firebase') {
      constructor() {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          // 这里填任意占位值,因为Firebase会自行处理签名校验
          secretOrKey: 'placeholder-secret',
        });
      }
    
      async validate(rawJwtToken: string) {
        try {
          const decodedToken = await getAuth().verifyIdToken(rawJwtToken);
          console.log('validate');
          return decodedToken;
        } catch (error) {
          throw new UnauthorizedException('无效的Firebase Token');
        }
      }
    }
    
  2. 修正模块中的拼写错误
    将auth.module.ts中的导入路径修正为正确的拼写:

    import { FirebaseStrategy } from './firebase.strategy';
    
  3. 优化路由语义
    @Get('login')路由搭配FirebaseAuthGuard语义矛盾——登录接口是用来获取Token的,不应要求携带Token访问。建议将受保护的接口改为其他路由,例如:

    @UseGuards(FirebaseAuthGuard)
    @Get('profile')
    async getProfile(@Request() req) {
      return req.user;
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:35:20