Nest无法解析UserRepository依赖,登录用例跨模块访问问题
错误原因
你遇到的Error: Nest can't resolve dependencies of the UserRepository (?)是因为AuthModule里重复创建了UserRepository的提供者,但这个新实例需要的UserModel(Mongoose模型)并没有在AuthModule的上下文里注册——只有UserModule导入了MongooseModule.forFeature来配置User模型,AuthModule自己没配置,所以Nest找不到这个依赖。
而UserController能正常访问是因为它属于UserModule,直接使用的是UserModule中已经配置好模型依赖的UserRepository实例。
最佳解决方案:复用UserModule导出的Repository
跨模块访问Repository的标准方式是在提供者模块(UserModule)导出Repository,然后在消费模块(AuthModule)导入该提供者模块,不需要重复创建提供者。具体修复步骤如下:
1. 调整UserModule:导出令牌形式的Repository(可选但推荐)
如果希望基于接口注入(符合DDD原则),可以在UserModule里把Repository注册为令牌提供者并导出:
// user.module.ts import { Module } from '@nestjs/common'; import { UserController } from '../../controllers/user/user.controller'; import { MongooseModule } from '@nestjs/mongoose'; import UserRepository from '../../repository/mongoose/user/user.repository'; import { User, UserSchema } from '../../repository/mongoose/user/user.model'; @Module({ imports: [ MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), ], controllers: [UserController], providers: [ { provide: 'UserRepository', // 注册令牌 useClass: UserRepository, }, ], exports: ['UserRepository'], // 导出令牌,让其他模块能注入 }) export class UserModule {}
2. 清理AuthModule:移除重复的提供者
AuthModule不需要自己创建UserRepository、JwtService、BcryptService的提供者,因为:
- UserRepository可以直接从UserModule导入使用
- JwtModule已经全局注册,JwtService可直接注入
- BcryptModule如果已经导出了BcryptService,导入后即可使用
修改后的AuthModule:
// auth.module.ts import { Module } from '@nestjs/common'; import { AuthController } from '../../controllers/auth/auth.controller'; import { JwtModule } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; import LoginUseCase from '../../../usecase/auth/login.usecase'; import { JwtStrategy } from '../../common/strategies/jwt-strategy'; import { UserModule } from '../user/user.module'; import { BcryptModule } from '../bcrypt/bcrypt.module'; @Module({ imports: [ JwtModule.register({ global: true, secret: process.env.JWT_SECRET, signOptions: { expiresIn: '1h' }, }), PassportModule, UserModule, // 导入UserModule,就能使用它导出的Repository BcryptModule, ], controllers: [AuthController], providers: [LoginUseCase, JwtStrategy], // 移除重复的提供者 exports: [LoginUseCase], }) export class AuthModule {}
3. 调整LoginUseCase的注入(保持原有令牌注入方式)
因为我们在UserModule里注册了'UserRepository'令牌,所以LoginUseCase的注入代码不需要修改,保持原样即可:
// login.usecase.ts constructor( @Inject('UserRepository') private userRepository: UserRepository, private jwtService: JwtService, // 直接注入全局的JwtService,不需要@Inject('JwtService') @Inject('BcryptService') private bcryptService: IBcryptService, ) {}
注:JwtService可以直接注入,不需要用
@Inject('JwtService'),因为JwtModule注册的是类提供者。
额外优化:避免全局模块冗余
你的AppModule里重复注册了JwtModule和PassportModule,而AuthModule里已经注册了全局的JwtModule,所以可以把AppModule里的JwtModule和PassportModule移除,减少冗余。
核心总结
跨模块共享依赖的正确姿势是:
- 提供者模块(如UserModule):注册依赖并导出它
- 消费模块(如AuthModule):导入提供者模块,直接注入使用
- 不要在消费模块里重复创建相同的提供者,否则会导致依赖上下文不一致
内容的提问来源于stack exchange,提问作者Lole

