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

NestJS中Refresh Token刷新AccessToken时属性访问undefined问题

问题描述

搭建带有JWT Token和Refresh Token的NestJS API时,调用Refresh Token获取新AccessToken出现异常:refreshToken函数生成AccessToken时Payload为空。打印user对象能看到完整属性值,但访问user.id、user.username等属性均返回undefined。


相关代码

Refresh JWT策略代码

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';

@Injectable()
export class RefreshJwtStrategy extends PassportStrategy(
  Strategy,
  'jwt-refresh',
) {
  constructor(private readonly configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromBodyField('refresh'),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('jwt.refreshSecret'),
    });
  }

  async validate(payload: any) {
    return { user: payload.sub, userId: payload.userId };
  }
}

控制器代码

@UseGuards(RefreshJwtGuard)
@Post('/refresh')
 async refreshToken(@Request() req) {
    return await this.authService.refreshToken(req.user);
  }

refreshToken函数代码

async refreshToken(user: User) {
    console.log(user); // 能正常打印用户对象及属性值
    const payload = {
      userId: user.id, // undefined
      sub: {
        id: user.id, // undefined
        username: user.username, // undefined
        email: user.email, // undefined
      },
    };
    console.log(payload); // 输出为空结构
    return {
      accessToken: this.jwtService.sign(payload),
    };
  }

日志输出

user打印结果

{
  user: {
    id: '8c5370bd-3b5c-404c-8362-fdb6efb84d75',
    username: 'owner1.1',
    email: 'owner1.1@gmail.com'
  },
  userId: '8c5370bd-3b5c-404c-8362-fdb6efb84d75'
}

payload打印结果

{
  userId: undefined,
  sub: { id: undefined, username: undefined, email: undefined }
}

问题原因

从日志可见,req.user的结构是{ user: {...}, userId: ... },但你在refreshToken函数里直接访问user.id,这是结构层级错误——真实的用户属性嵌套在user.user字段下,而非req.user的顶级属性。

根源在RefreshJwtStrategy的validate方法:你返回的对象将用户信息嵌套在user字段中,导致req.user的结构不符合后续代码的访问逻辑。


解决方法

方法一:调整validate方法的返回值

让validate直接返回用户信息,使req.user成为用户对象本身:

async validate(payload: any) {
  // 直接返回payload.sub中的用户信息
  return payload.sub;
}

若需保留userId字段,可合并返回:

async validate(payload: any) {
  return { ...payload.sub, userId: payload.userId };
}

方法二:修正refreshToken函数的属性访问路径

若不想改动策略代码,就在refreshToken中正确访问嵌套的属性:

async refreshToken(user: any) {
  const payload = {
    userId: user.userId,
    sub: {
      id: user.user.id,
      username: user.user.username,
      email: user.user.email,
    },
  };
  return {
    accessToken: this.jwtService.sign(payload),
  };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:27:43