使用 NestJS 解决依赖关系

Resolving dependencies with NestJS

我有相当深厚的 MERN stack/Javascript 背景,我今天正在尝试新技术:NestJS,据我所知,它是围绕 TypeScrypt 和 OOP 编程构建的。

我正在尝试构建一个简单的 API,并通过 JSON Web 令牌进行身份验证,因此我按照文档所述实施了 Guard。请注意,我没有通过使用 Passport 及其策略来走完整的“NestJS”路线。在发现新技术时,我更喜欢用尽可能少的库来实现我自己的东西,而不是对我第二天不会记得的教程进行完整的复制粘贴。

我成功编写了简单的路由并使用 Mongoose 和 MongoDB 连接了项目,但我偶然发现了一个关于 NestJS 模块 imports/exports 层次结构的奇怪错误。

错误如下:

[Nest] 37422  - 03/25/2022, 4:49:57 PM   ERROR [ExceptionHandler] Nest can't resolve dependencies of the JwtAuthGuard (?). Please make sure that the argument ConfigService at index [0] is available in the UsersModule context.

现在我使用 ConfigModule,特别是 ConfigService 来访问我的环境变量。我将在我的 JwtAuthGuard 中需要它来访问我的私钥和各种 JWT 配置到 create/verify 令牌。

我声明我的 JwtAuthGuard 如下:

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { ConfigService } from '@nestjs/config';
const jwt = require('jsonwebtoken');

@Injectable()
export class JwtAuthGuard implements CanActivate {
  constructor(private config: ConfigService) {}
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const req = context.switchToHttp().getRequest();
    // extract Authorization header and verify it here

    // return true/false depending on jwt.verify return
    return false;
  }

  createToken() {
    return jwt.sign(
      { issuer: this.config.get('JWT_ISSUER') },
      this.config.get('JWT_PRIVATE_KEY'),
      { algorithm: this.config.get('JWT_ALGORITHM') },
    );
  }
}

当然,我在 JwtAuthModule:

中导入 ConfigModule
import { Module } from '@nestjs/common';
import { JwtAuthGuard } from './guard';
import { ConfigModule } from '@nestjs/config';

@Module({
  exports: [JwtAuthGuard],
  providers: [JwtAuthGuard],
  imports: [ConfigModule],
})
export class JwtAuthModule {}

我的 UsersModule(最初)看起来像这样:

import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './schemas/users';
import { UsersController } from './controller';
import { UsersProvider } from './service';
import { JwtAuthModule } from '../jwt-auth/module';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    JwtAuthModule,
  ],
  controllers: [UsersController],
  providers: [UsersProvider],
  exports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    UsersProvider,
  ],
})
export class UsersModule {}

我说 最初 因为,在仔细阅读错误之后,我摆弄了代码并看到了当我:

错误消失,一切正常。

问题是:为什么我必须让 ConfigModule 可供 UsersModule 使用,而实际上它本身并不真正需要它?


编辑:忘记添加上下文:我在我的 UsersController routes/handlers.

之一上使用 @UseGuards(JwtAuthGuard) 装饰器

根据错误,我只是假设您的 UsersController 中某处有 @UseGuards(JwtAuthGuard)。通过这个,Nest 将尝试在 UsersModule 上下文的上下文中实例化 JwtAuthGuard,这意味着使用它可用的依赖项。由于您的 JwtAuthGuard 使用 ConfigServiceConfigModule 的导出需要可用,这可以通过让 JwtAuithModule 导入和导出 ConfigModule 来完成] 或者让 UsersModule 导入 ConfigModule.

exports: [JwtAuthGuard] 还不够的原因有点奇怪,因为增强器不是提供者,因为它们每次都使用相同的 pre-built 上下文来构建。它们在技术上不属于模块(至少在大多数情况下,存在超出此答案范围的例外情况)所以即使 JwtAuthModule 确实导出 JwtAuthGuard 它不实际上意味着 Nest 将使用导出的提供程序从 @UseGuards() 中的 UserModule 中创建实例 UserController.

希望一切都有意义