NestJS中如何通过AccessToken获取关联Profile的当前登录用户数据
问题描述
我想要获取当前登录用户的详细数据,包含User表和关联的Profile表的数据,但使用access token识别当前登录用户时,无法获取到与User表关联的Profile数据。
User表实体定义
@PrimaryGeneratedColumn('increment') id: number; @Column() userName: string; @Column({ unique: true, nullable: true }) email: string; @Column({ unique: true }) phoneNumber: string; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @OneToOne(() => Profile, (profile) => profile.user) profile: Profile; refreshTokens: UserRefreshToken[];
Profile表实体定义
@Entity() export class Profile extends BaseEntity { @PrimaryGeneratedColumn('increment') id: number; @Column({ nullable: true }) name: string; @Column({ nullable: true }) gender: string; @Column({ nullable: true }) phoneNumber: string; @Column({ nullable: true }) email: string; @Column({ nullable: true }) nrm: string; @Column({ nullable: true }) birthDate: Date; @CreateDateColumn({ nullable: true }) createdAt: Date; @UpdateDateColumn({ nullable: true }) updatedAt: Date; @OneToOne(() => Users) @JoinColumn() user: Users; }
获取当前登录用户的控制器代码
import { Controller, Get, UseGuards } from '@nestjs/common'; import { ProfileService } from './profile.service'; import { accessTokenGuard } from 'src/guards/access-token.guard'; import { GetUser } from 'src/modules/auth/get-user-decorator'; import { Users } from '../users/entity/users.entity'; @Controller('profile') export class ProfileController { constructor(private service: ProfileService) {} @UseGuards(accessTokenGuard) @Get() async getData(@GetUser() user: Users) { return user; // 示例:获取当前登录用户 } }
自定义GetUser装饰器代码
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export const GetUser = createParamDecorator( (_data, ctx: ExecutionContext): any => { const req = ctx.switchToHttp().getRequest(); console.log(req.user); return req.user; }, );
当前得到的响应
{ "id": 41, "userName": "73748484", "email": null, "phoneNumber": "74747474", "createdAt": "2023-06-25T07:35:57.467Z", "updatedAt": "2023-06-25T07:35:57.461Z" }
期望的响应(无需再次查询数据库,仅通过access token获取)
{ "id": 41, "userName": "1288383838", "email": null, "phoneNumber": "737373838", "createdAt": "2023-06-25T07:35:57.467Z", "updatedAt": "2023-06-25T07:35:57.461Z", "profile": { "id": 36, "name": "Profile Name", "gender": "Male", "phoneNumber": "3737737473747", "email": "", "nrm": "99.jejejdj.05", "birthDate": "1999-09-07T08:00:00.000Z", "createdAt": "2023-06-25T07:36:32.586Z", "updatedAt": "2023-06-25T07:36:32.586Z" } }
解决方案
要实现通过access token直接返回包含Profile的用户数据,核心是生成access token时就把关联的Profile数据存入token payload,验证token后就能直接从req.user中拿到完整数据,无需二次查询数据库。
1. 修改JWT生成逻辑,加入Profile数据
在生成access token的代码(比如AuthService的登录方法)中,查询用户时关联加载Profile,再将用户和Profile数据一起存入JWT payload:
// AuthService示例代码 async login(loginDto: LoginDto) { // 查询用户时关联加载profile const user = await this.usersRepository.findOne({ where: { phoneNumber: loginDto.phoneNumber }, relations: ['profile'], // 关键:加载关联的Profile }); // 此处省略用户验证逻辑... // 构造payload,包含用户和profile数据 const payload = { sub: user.id, userName: user.userName, email: user.email, phoneNumber: user.phoneNumber, profile: user.profile, // 将profile加入payload }; // 生成access token const accessToken = this.jwtService.sign(payload); return { accessToken }; }
2. 确保Guard验证后完整解析payload
如果使用自定义的accessTokenGuard,要确保验证token后将完整payload挂载到req.user上:
// 自定义accessTokenGuard示例 async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); const token = this.extractTokenFromHeader(request); if (!token) { throw new UnauthorizedException(); } try { // 验证token并解析完整payload const payload = await this.jwtService.verifyAsync(token, { secret: process.env.JWT_SECRET }); // 将完整payload赋值给req.user request.user = payload; } catch { throw new UnauthorizedException(); } return true; }
如果使用NestJS内置的AuthGuard('jwt'),默认会自动将完整payload解析到req.user,无需额外修改。
3. 实体关联优化(可选)
如果后续需要从数据库查询时自动加载Profile,可以在User实体的@OneToOne装饰器中添加{ eager: true },但这仅影响数据库查询,不改变JWT payload内容:
// User实体中修改关联配置 @OneToOne(() => Profile, (profile) => profile.user, { eager: true }) profile: Profile;
调整完成后,通过@GetUser()拿到的user对象就会包含完整的Profile数据,和期望的响应一致,且无需二次查询数据库。
内容的提问来源于stack exchange,提问作者Robby Izhar Ramadhana
相关产品推荐
相关产品推荐

