NestJS全局AuthGuard未在所有端点触发问题求助
问题描述
按照NestJS文档配置了AuthGuard与PassportStrategy(Strategy, "oidc"),但该Guard仅在部分控制器触发,其余控制器的请求会直接进入处理逻辑,完全跳过Guard校验。请问可能的诱因是什么?如何解决?
代码示例
oidc.strategy.ts
import { env } from "process"; import { Injectable, UnauthorizedException } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { ExtractJwt, Strategy, StrategyOptions } from "passport-jwt"; import { passportJwtSecret } from "jwks-rsa"; @Injectable() export class OidcStrategy extends PassportStrategy(Strategy, "oidc") { constructor() { console.log("OidcStrategy"); super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKeyProvider: passportJwtSecret({ cache: true, rateLimit: true, jwksRequestsPerMinute: 5, jwksUri: env.JWKS_URI as any, }), audience: env.AUDIENCE as any, issuer: env.ISSUER as any, } as StrategyOptions); console.log("end OidcStrategy"); } async validate(payload: any) { console.log("validate"); if (!payload) { throw new UnauthorizedException("Invalid token"); } return { userId: payload.sub, policy: [], ...payload, }; } }
oidc.guard.ts
import { ExecutionContext, Injectable } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; import { AuthGuard } from "@nestjs/passport"; @Injectable() export class OidcAuthGuard extends AuthGuard("oidc") { constructor(private readonly reflector: Reflector) { super(); } async canActivate(context: ExecutionContext) { const isHealthCheck = this.reflector.getAllAndOverride<boolean>("health", [ context.getHandler(), context.getClass(), ]); if (isHealthCheck) return true; console.log("OidcAuthGuard canActivate"); return super.canActivate(context) as boolean; } }
app.module.ts
@Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, }), TypeOrmModule.forRootAsync(ORMconfig), ServeStaticModule.forRootAsync({ imports: [ConfigModule], inject: [Config], extraProviders: [Config], useFactory: async (config: Config) => { return [ { rootPath: config.Path, serveRoot: "/images", }, ]; }, }), PingModule, HealthCheckModule, LoggerModule, UtilsModule, UserModule, ], controllers: [], providers: [ OidcStrategy, Config, { provide: APP_GUARD, useClass: OidcAuthGuard, }, ], exports: [], }) export class AppModule {}
example.controller.ts
@UseFilters(GeneralExceptionFilter) @Controller("example") @ApiTags("example") export class ExampleController { constructor(private readonly exampleService: ExampleService) {} @Post("example") @ApiOperation({ summary: "Create a new example" }) @ApiResponse({ status: 200, description: "Example created successfully", type: InitExampleDto, }) @ApiResponse({ status: 500, description: "Internal server error" }) initExample(@Body() createExampleDto: CreateExampleDto) { return this.exampleService.initExample(createExampleDto); } }
example.module.ts
@Module({ imports: [ TypeOrmModule.forFeature( [Examples], DbConnections.ExampleDatabase ), ExternalApiModule, UtilsModule, LoggerModule, UserModule, ], controllers: [ExampleController], providers: [ExampleService, ExternalAPIsConfig, FileSystemUtilsService], }) export class ExampleModule {}
可能的诱因与解决方案
1. 目标模块未导入根模块
从代码可见,ExampleModule并未添加到AppModule的imports数组中。NestJS全局守卫(通过APP_GUARD注册)仅作用于根模块及其导入的子模块控制器,未导入的模块不会触发全局守卫。
解决方法:在AppModule的imports中添加ExampleModule:
// app.module.ts @Module({ imports: [ // ...其他已导入模块 ExampleModule, // 添加此行 ], // ...其余配置 }) export class AppModule {}
2. 子模块重复注册全局守卫
如果子模块(如ExampleModule)自行注册了APP_GUARD,会覆盖根模块的全局守卫配置,导致原Guard失效。
解决方法:检查所有子模块的providers配置,移除重复的APP_GUARD注册。若子模块需要自定义守卫,建议通过@UseGuards()装饰器绑定局部守卫,而非全局守卫。
3. 控制器/方法被标记为跳过守卫
你的OidcAuthGuard通过Reflector检查health元数据,若某些控制器或方法被设置了该元数据(或其他跳过守卫的元数据),会直接跳过校验。
解决方法:排查所有控制器和路由方法,确认是否存在无意添加的跳过守卫元数据。若确需跳过特定路由,需确保符合业务需求。
4. 策略名称不匹配
虽然你的代码中PassportStrategy(Strategy, "oidc")与AuthGuard("oidc")名称匹配,但如果其他策略存在名称错误,也会导致Guard失效。
解决方法:确保所有自定义Guard传入的策略名称与对应PassportStrategy的第二个参数完全一致。
5. 全局过滤器/拦截器干扰守卫执行
NestJS执行顺序为守卫优先于过滤器,但如果全局过滤器(如GeneralExceptionFilter)存在异常逻辑(如提前返回响应),可能会跳过守卫校验。
解决方法:检查GeneralExceptionFilter实现,确保它仅在捕获异常时处理响应,不提前终止请求流程。
内容的提问来源于stack exchange,提问作者idan ovadia

