我目前正在为守卫中的服务注入(inject)而苦苦挣扎。
好吧,我做了一个 JwtAuthGuard
,它需要我的 FirebaseService
和 UserService
。
所以我认为创建一个 AuthGuardModule
会很有用,所以我只需要在具有 Controller
的模块中导入我的 AuthGuardModules
>,使用我的守卫。
不幸的是,我的 UserModule
也需要这个守卫。
所以当我在我的 UserModule
中导入我的 AuthGuardModule
时,我得到一个 Circular Dependency Error
是很自然的。
然后,我在 Nest.js 中尝试了所有与 Circular Dependency Error
或多或少相关的事情,但无能为力。
有人可以告诉我如果:
- 我想只为我的守卫制作一个模块是完全错误的吗?
- 如果不是,我该如何修复我的
Circular Dependency Error
? - 如果我误解了那部分,为什么它不对,最好的方法是什么?
JwtAuthGuard
@Injectable()
export class JwtAuthGuard implements CanActivate {
private readonly logger = new Logger(JwtAuthGuard.name)
constructor(
private readonly firebaseService: FirebaseService,
private readonly userService: UserService
) { }
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization'];
if (!token) {
throw new UnauthorizedException
}
try {
const firebaseUser = await this.firebaseService.getUserByToken(token)
request.user = await this.userService.getByEmail(firebaseUser.email)
return true
} catch (error) {
this.logger.error(this.canActivate.name, error)
throw new UnauthorizedException
}
}
}
AuthGuardModule
@Module({
imports: [UserModule],
providers: [FirebaseService, JwtAuthGuard],
exports: [JwtAuthGuard]
})
export class AuthGuardModule {}
编辑
好吧,NestJS discord 的 jmcdo29 向我解释说:
Your
AuthGuardModule
should export theUserModule
and theFirebaseService
. Guards, when used in the@UseGuards()
decorator, are used in the context of the current controller's module, instead of being looked at as anInjectable
provider
所以我这样做了,它确实解决了我最初的问题,但我还有另一个循环依赖问题。
首先,让我们恢复一下我的架构:
授权模块
- 它处理注册路由,以及发送一些电子邮件的路由,如密码重置或电子邮件验证。
- 当我调用 register 路由时,它需要
UserModule
在我的数据库中创建一个用户
@Module({
imports: [
AuthGuardModule
],
controllers: [AuthController],
providers: [AuthService, EmailService, FirebaseService],
})
export class AuthModule {}
文件模块
- 它处理文件的上传和删除。
@Module({
imports: [
forwardRef(() => AuthGuardModule),
BlobModule,
MongooseModule.forFeature([{ name: File.name, schema: FileSchema }])
],
controllers: [FileController],
providers: [FileService],
exports: [FileService],
})
export class FileModule {}
用户模块
- 它处理所有用户路由。
- 它需要
FileModule
,在修改头像时检查头像是否存在(我只有一个路径可以更新我所有用户的个人数据) - 它还需要
AuthGuardModule
来使用我的JwtAuthGuard
@Module({
imports: [
forwardRef(() => AuthGuardModule),
forwardRef(() => FileModule),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])
],
controllers: [UserController],
providers: [UserService, FirebaseService],
exports: [UserService, FileModule]
})
export class UserModule {}
AuthGuardsModule
- 它包含我的 JWT 检查守卫,然后我检查我的数据库中的用户是否链接到已连接的用户
- 它需要
UserModule
来获取我的数据库中的用户
@Module({
imports: [forwardRef(() => UserModule), FirebaseModule],
providers: [JwtAuthGuard, RegisterAuthGuard],
exports: [JwtAuthGuard, RegisterAuthGuard, FirebaseModule, UserModule]
})
export class AuthGuardModule {}
我可以使用 firebase 来存储我的用户头像并在前端进行,但我必须将它存储在 Azure Blob 存储中(这是强加给我的),所以 FileModule 会处理所有这些事情
所以,现在,感谢你们,我解决了我的 AuthGuardsModule -> UserModule 循环依赖,我有一个新的循环依赖问题:AuthGuardsModule -> UserModule -> FileModule
我在 FileModule 中设置了 AuthGuardsModule 的 forwardRef,但 nest 自然地告诉我要确保双向关系的每一侧都用“forwardRef()”装饰
所以我在 UserModule
中将 forwardRef
导入到我的 FileModule
中,但同样如此。
有什么想法吗?
最佳答案
从我的角度来看,您需要使用 @nestjs/common
包中的 forwardRef
方法,它负责在循环依赖发生时处理它.参见 Circular dependency - NestJS docs
需要考虑的一件事是您的 JwtAuthGuard
的位置。它最初是在 AuthModule
中还是在另一个共享模块中?
我假设守卫最初在您的 AuthModule
中(例如,假设 /src/auth/guards/auth-guard.ts
)。
我还假设 FirebaseService
位于 FirebaseModule
中并从那里导出,并且 FirebaseModule
可注入(inject)不需要其他类取决于其他循环引用类/模块。 (在这种情况下,您需要通过在涉及的类/模块中添加更多 forwardRef
来指示 Nest 应如何处理它)
根据您提供的代码,您可以执行如下操作:
授权模块
@Module({
imports: [forwardRef(() => UserModule), FirebaseModule],
providers: [...yourProviders],
exports: [...yourExportedInjectables]
})
export class AuthModule {}
FirebaseModule
@Module({
imports: [...requiredImports],
providers: [FirebaseService],
exports: [FirebaseService]
})
export class FirebaseModule {}
用户模块
@Module({
imports: [forwardRef(() => AuthModule)],
providers: [...yourProviders],
exports: [...yourExportedInjectables]
})
export class UserModule {}
注意:您还可以根据具体用例在服务层使用forwardRef
。
NB2:守卫可以在一个共享模块中分组,该模块可以导入到 AuthModule
中,这样您就不必指定 Nest 在每个模块之间转发引用,而只需引用 AuthModule
在使用给定守卫的模块中。
希望对你有帮助!
同样,我对您的架构了解不多,因此我提供了基于假设的代码示例。
不要犹豫,发表评论/提供更多上下文,以便我可以相应地编辑我的答案。
关于typescript - Guards 和循环依赖中的服务注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71778848/