NestJS升级TypeORM0.3后Guard守卫无法访问Repository如何解决
NestJS守卫中访问TypeORM 0.3+ Repository的正确实现
注入失败的核心原因
之前构造函数注入Repository不生效,基本是两个问题导致的:
- 注册守卫时手动new了实例(比如在main.ts里调用
app.useGlobalGuards(new XxxGuard())),手动创建的实例脱离Nest依赖注入容器,无法获取容器内的托管实例 - 守卫所在模块/使用守卫的模块,没有提前通过
TypeOrmModule.forFeature([User])注册对应实体的Repository,容器内找不到对应依赖
方案一:通过APP_GUARD令牌注册守卫(官方推荐)
这是最符合NestJS依赖注入设计的实现方式,不需要修改原有业务逻辑,直接支持Repository注入:
- 在对应业务模块(比如存放User实体的UserModule)中,导入实体对应的TypeORM特征模块,同时用
APP_GUARD令牌注册你的守卫,不需要手动导出:
// user.module.ts import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from './user.entity'; import { YourAuthGuard } from './your-auth.guard'; @Module({ imports: [TypeOrmModule.forFeature([User])], // 注册当前模块用到的实体Repository providers: [ { provide: APP_GUARD, useClass: YourAuthGuard, }, ], }) export class UserModule {}
- 守卫内直接按正常方式注入Repository即可:
// your-auth.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './user.entity'; @Injectable() export class YourAuthGuard implements CanActivate { constructor( @InjectRepository(User) private readonly userRepo: Repository<User>, ) {} async canActivate(context: ExecutionContext): Promise<boolean> { // 直接调用this.userRepo执行数据库操作 const user = await this.userRepo.findOneBy(/* 你的查询条件 */); return !!user; } }
注意:如果守卫不需要全局生效,只需要在特定路由上通过@UseGuards(YourAuthGuard)使用,只要保证使用守卫的模块已经导入了注册过User实体的TypeOrmModule即可,不需要额外把守卫注册为全局提供者。
方案二:通过ModuleRef获取已初始化的数据源实例
如果不想调整守卫注册方式,可以直接在守卫内通过模块引用拿已经初始化好的DataSource实例,不需要新建数据库连接:
// your-auth.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import { DataSource } from 'typeorm'; import { User } from './user.entity'; @Injectable() export class YourAuthGuard implements CanActivate { constructor(private readonly moduleRef: ModuleRef) {} async canActivate(context: ExecutionContext): Promise<boolean> { // 从DI容器获取已经初始化完成的数据源,不会新建连接 const dataSource = this.moduleRef.get(DataSource, { strict: false }); const userRepo = dataSource.getRepository(User); // 执行数据库操作 const user = await userRepo.findOneBy(/* 你的查询条件 */); return !!user; } }
避坑提示:不要在守卫内手动传入配置新建数据库连接,会造成连接数泄漏;TypeORM 0.3版本已经移除了
getConnection这类全局静态方法,多数据源场景下这类静态方法会出现连接错乱问题,不要继续使用。
内容的提问来源于stack exchange,提问作者TomFree
相关产品推荐
相关产品推荐

