NestJS GraphQL中如何为@ResolveField使用@UseGuards装饰器
NestJS GraphQL 字段级权限控制实现方案
需求场景
- 主查询接口公开可访问,无权限拦截
- 返回结果中的特定敏感字段仅对指定身份用户可见
- 约束条件:不新增额外数据查询、不使用字段守卫以外的其他权限控制方式
具体实现
1. 主查询保持公开无守卫
主查询对应的@Query方法不挂载任何权限守卫,仅处理公开数据的查询逻辑,保证匿名/所有用户都能正常请求拿到公开字段数据:
@Resolver(() => Article) export class ArticleResolver { constructor(private articleService: ArticleService) {} // 无任何守卫,公开可访问 @Query(() => Article) async article(@Args('id') id: number) { return this.articleService.getById(id); } }
2. 敏感字段单独挂载字段级守卫
需要权限控制的字段不要在主查询里直接返回,单独写@ResolveField解析方法,仅在这个方法上挂载@UseGuards,不影响主查询和其他公开字段:
// 同ArticleResolver内补充字段解析逻辑 @ResolveField(() => String, { nullable: true }) @UseGuards(ArticleSensitiveGuard) // 仅敏感字段挂守卫 async sensitiveContent(@Parent() article: Article) { // 守卫校验通过才会执行到这里,返回真实敏感内容 return article.sensitiveContent; }
3. 自定义守卫适配无额外查询逻辑
守卫内部直接从GraphQL上下文取已解析好的用户信息、父级查询已经返回的实体数据做权限判断,不需要重复查库:
@Injectable() export class ArticleSensitiveGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const gqlCtx = GqlExecutionContext.create(context); const request = gqlCtx.getContext().req; const currentUser = request.user; // 取全局身份解析逻辑已经挂在req上的用户信息,无额外查询 const targetArticle = gqlCtx.getParent<Article>(); // 取主查询已经查出的文章实体,无额外查询 // 自定义权限规则:仅文章作者、平台管理员可见敏感字段 return currentUser?.id === targetArticle.authorId || currentUser?.role === 'admin'; } }
效果说明
- 未授权用户请求主查询时,可以正常拿到标题、正文、发布时间等公开字段,
sensitiveContent字段自动返回null - 符合权限要求的用户请求时,可以拿到完整的所有字段值
- 整个流程没有新增任何额外数据库查询,仅使用
@ResolveField上挂载的守卫完成权限控制,完全匹配需求
注意:记得给敏感字段设置
nullable: true,否则未授权时会直接抛权限异常中断整个请求,而不是仅隐藏敏感字段。
内容的提问来源于stack exchange,提问作者johnykes
相关产品推荐
相关产品推荐

