NestJS GraphQL场景下如何优雅地条件启用身份认证策略?
解决方案
核心原因是AuthGuard()是一个返回类的mixin函数,传入的策略列表参数需要在类定义阶段就确定,而Nest依赖注入的初始化是在类定义完成之后,所以无法直接在继承参数位置注入配置服务,你可以用以下两种方案实现配置统一管理:
方案1:静态配置文件(最简单)
适合所有配置在应用启动时就固定的场景,直接把策略列表放到独立的配置文件中统一维护:
- 新建配置文件
src/config/auth.config.ts:
// src/config/auth.config.ts export const authConfig = { strategies: process.env.DEBUG ? ['firebase', 'debug'] : ['firebase'], // 其他认证相关配置可以统一放在这里 };
- 修改
GqlAuthGuard的实现,直接导入配置使用:
import { ExecutionContext, Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { GqlExecutionContext } from '@nestjs/graphql'; import { authConfig } from 'src/config/auth.config'; @Injectable() export class GqlAuthGuard extends AuthGuard(authConfig.strategies) { getRequest(context: ExecutionContext) { const ctx = GqlExecutionContext.create(context); return ctx.getContext().req; } }
方案2:结合ConfigService动态生成(更灵活)
如果你用@nestjs/config做统一配置管理,需要从环境变量、远程配置中心动态拉取策略列表,可以用工厂函数动态创建Guard类:
- 先在配置文件
src/config/configuration.ts中定义策略配置:
// src/config/configuration.ts export default () => ({ auth: { strategies: process.env.DEBUG ? ['firebase', 'debug'] : ['firebase'], }, // 其他全局配置 });
- 编写Guard工厂函数,在模块中通过
useFactory动态生成实例:
// src/auth/gql-auth.guard.ts import { ExecutionContext, Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { GqlExecutionContext } from '@nestjs/graphql'; import { ConfigService } from '@nestjs/config'; // 动态创建Guard的工厂函数 export function createGqlAuthGuard(strategies: string[]) { @Injectable() class GqlAuthGuard extends AuthGuard(strategies) { getRequest(context: ExecutionContext) { const ctx = GqlExecutionContext.create(context); return ctx.getContext().req; } } return GqlAuthGuard; } // 在AuthModule中注册动态Guard @Module({ imports: [ConfigModule], providers: [ { provide: 'GQL_AUTH_GUARD', useFactory: (configService: ConfigService) => { const strategies = configService.get<string[]>('auth.strategies'); return createGqlAuthGuard(strategies); }, inject: [ConfigService], }, ], exports: ['GQL_AUTH_GUARD'], }) export class AuthModule {}
- 使用的时候直接注入对应的token即可:
// 在Resolver中使用 @Resolver() @UseGuards('GQL_AUTH_GUARD') export class UserResolver {} // 如果是全局Guard,也可以在main.ts中直接初始化 async function bootstrap() { const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); const strategies = configService.get<string[]>('auth.strategies'); const GqlAuthGuard = createGqlAuthGuard(strategies); app.useGlobalGuards(new GqlAuthGuard()); await app.listen(3000); }
内容的提问来源于stack exchange,提问作者synic
相关产品推荐
相关产品推荐

