NestJs Guards执行顺序异常求助:AbilityGuard先于AuthGuard执行
问题分析与修复方案
核心问题:守卫执行顺序异常
按NestJS官方规则,控制器级守卫应优先于路由(方法)级守卫执行,但你遇到AbilitiesGuard先运行的情况,大概率是因为控制器上的JwtAuthenticationGuard没有被Nest正确管理,或者守卫的声明方式导致顺序错乱。另外你的AbilitiesGuard里还有个潜在的取值逻辑错误。
具体修复步骤
1. 修正JwtAuthenticationGuard的声明方式
你的JwtAuthenticationGuard缺少@Injectable()装饰器,且控制器上用new手动实例化,这会导致Nest无法按正常生命周期管理它。修改如下:
import { AuthGuard } from '@nestjs/passport'; import { Injectable } from '@nestjs/common'; @Injectable() // 添加装饰器,让Nest可以依赖注入管理 export class JwtAuthenticationGuard extends AuthGuard('jwt') {}
然后控制器上改为使用类声明守卫,不要手动new:
@ApiTags('Tenant') @Controller('tenant') @UseGuards(JwtAuthenticationGuard) // 用类引用,而非手动实例化 export class TenantController { // ... 原有代码 }
2. 明确守卫执行顺序
如果只需要当前路由做权限校验,直接在路由上按认证在前、权限在后的顺序声明两个守卫:
@Post() @CheckAbilities({action: UserAction.CREATE, subject: User}) @UseGuards(JwtAuthenticationGuard, AbilitiesGuard) // 顺序不能反,先完成身份认证 async create(@CurrentUser() user: User, @Body() createTenantDto: CreateTenantDto) { try { return await this._tenantService.create(user,createTenantDto); } catch (error) { throw error; } }
如果所有路由都需要JWT认证,保留控制器级的JwtAuthenticationGuard即可,此时控制器级守卫会先执行,再执行路由级的AbilitiesGuard。
3. 修复request.user的取值逻辑
JWT AuthGuard默认会把用户对象直接绑定到request.user,你当前的解构逻辑存在错误,应改为:
const request = context.switchToHttp().getRequest(); const user = request.user; // 直接取request.user,无需额外解构 console.log(user); const ability = this.abilityFactory.defineAbility(user);
如果你的JWT策略validate方法返回的是{ user: 实体对象 }格式,才需要用const { user } = request.user;,否则直接取request.user即可。
验证执行顺序
可以在两个守卫的canActivate方法中添加日志,确认执行顺序:
// JwtAuthenticationGuard async canActivate(context: ExecutionContext): Promise<boolean> { console.log('=== JWT认证守卫执行 ==='); return super.canActivate(context); } // AbilitiesGuard async canActivate(context: ExecutionContext): Promise<boolean> { console.log('=== 权限校验守卫执行 ==='); // ... 原有代码 }
调用接口后,控制台应先输出JWT守卫的日志,再输出权限守卫的日志,此时request.user就能正确获取到用户信息了。
内容的提问来源于stack exchange,提问作者DavidSch
相关产品推荐
相关产品推荐

