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

NestJS GraphQL无Passport实现AccessTokenGuard遇令牌无效错误求助

问题分析与解决方案

核心错误:令牌提取逻辑错误

你的extractTokenFromHeader方法中,分割Authorization头的方式完全错误:

private extractTokenFromHeader(authorization: string): string | undefined {
  const [_, token] = authorization?.split('') ?? []; // 用空字符串分割会拆分每个字符
  return token;
}

标准Authorization头格式是Bearer <token>,必须用空格分割才能正确提取令牌。空字符串分割会把每个字符拆成数组元素,导致拿到的不是完整令牌,直接触发验证失败。

修改后的提取方法

private extractTokenFromHeader(authorization: string): string | undefined {
  const [scheme, token] = authorization?.split(' ') ?? [];
  // 额外验证scheme是否为Bearer,提升鲁棒性
  return scheme?.toLowerCase() === 'bearer' ? token : undefined;
}

其他验证要点

1. GraphQL Context配置确认

你的GraphQLModule配置是正确的,已经将req注入到context中,Guard可以正常获取请求头:

context: ({ req }) => ({ req }),

2. JWT配置一致性检查

确保jwtConfig中的secret、expiresIn等参数,和生成AccessToken时的配置完全一致。比如生成令牌用的secret必须和验证时的secret完全相同,否则会出现invalid signature错误。

3. Playground请求格式检查

在GraphQL Playground中,必须在HTTP HEADERS标签中正确设置Authorization头:

{
  "Authorization": "Bearer your-real-access-token"
}

注意不要遗漏Bearer前缀和后面的空格,也不要在令牌前后加引号。

4. 错误日志精准排查

你的catch块已经打印了错误详情,查看控制台的JWT verification error可以快速定位问题:

  • invalid signature:生成和验证用的secret不匹配
  • jwt expired:令牌已过期
  • invalid token:令牌格式错误(比如未正确提取)

完整修正后的AccessTokenGuard代码

import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import { GqlExecutionContext } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';

import jwtConfig from 'src/iam/config/jwt.config';
import { REQUEST_USER_KEY } from 'src/iam/iam.constant';

@Injectable()
export class AccessTokenGuard implements CanActivate {
  constructor(
    private readonly jwtService: JwtService,
    @Inject(jwtConfig.KEY)
    private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const ctx = GqlExecutionContext.create(context);
    const { req } = ctx.getContext();

    const authorization = req?.headers?.authorization;
    if (!authorization) {
      throw new UnauthorizedException('缺少Authorization请求头');
    }

    const token = this.extractTokenFromHeader(authorization);
    if (!token) {
      throw new UnauthorizedException('令牌格式错误,需遵循Bearer <token>格式');
    }

    try {
      const payload = await this.jwtService.verifyAsync(
        token,
        this.jwtConfiguration,
      );
      req[REQUEST_USER_KEY] = payload;
      console.log('验证通过的用户信息:', payload);
    } catch (error) {
      console.error('JWT验证失败:', error.message);
      throw new UnauthorizedException(`令牌无效: ${error.message}`);
    }
    return true;
  }

  private extractTokenFromHeader(authorization: string): string | undefined {
    const [scheme, token] = authorization?.split(' ') ?? [];
    return scheme?.toLowerCase() === 'bearer' ? token : undefined;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 11:08:16