将服务注入 Nest.JS 中的守卫

Gre*_*ggy 10 node.js express nestjs

我有 KeysModule,可用于添加或删除 API 密钥。我需要这些密钥来保护某些路由免遭未经授权的访问。为了保护这些路由,我创建了 ApiGuard:

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

@Injectable()
export class ApiGuard implements CanActivate {

async canActivate(
    context: ExecutionContext,
  ): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    return request.headers.api_key;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我在路由中使用它:

 @Get('/protected')
 @UseGuards(ApiGuard)
 async protected(@Headers() headers: Api) {
   const key = await this.ks.findKey({ key: headers.api_key });
   if (!key || !key.active) return 'Invalid Key';
   return 'Your API key works';
 }
Run Code Online (Sandbox Code Playgroud)

其中 ks 是 KeyService 用于检查密钥是否正确。此解决方案有效,但很愚蠢。我必须在我想使用这个守卫的任何地方复制和粘贴一些代码行(我的意思是路线中的行)。

我试图将所有逻辑移至 ApiGuard,但出现错误,即 KeyService 无法注入 ApiGuard 类。解释一下,我在 KeysModule 的提供者中有 KeyService,但 ApiGuard 是全局使用的。

你知道怎么做吗?

Mys*_*rth 23

从 NestJS v8 开始,注入 zsoca 在接受的答案中回答的服务似乎不再起作用。

NestJS 8 的工作解决方案是提供类引用而不是字符串:

  constructor(@Inject(KeyService) private keyService: KeyService) {}
Run Code Online (Sandbox Code Playgroud)


小智 8

在守卫中注入服务。您可以创建一个全局模块。

// ApiModule
import {Module,Global} from '@nestjs/common';
import {KeyService} from '../';

@Global()
@Module({
    providers: [ KeyService ],
    exports: [KeyService]
})
export class ApiModule {}
Run Code Online (Sandbox Code Playgroud)

然后像这样将服务注入警卫

// guard
export class ApiGuard implements CanActivate {
constructor(@Inject('KeyService') private readonly KeyService) {}
}
 async canActivate(context: ExecutionContext) {
    // your code
    throw new ForbiddenException();
  }
Run Code Online (Sandbox Code Playgroud)

现在问题可以解决了。但我还有一个问题。我想注入一些东西到服务中,但得到了这个错误:

Nest 无法解析 AuthGuard (?, +) 的依赖项。请确保索引 [0] 处的参数在当前上下文中可用。

这是我的解决方案:

在 KeyService 中注入其他依赖项,如nestjs 文档所说。

从任何模块外部注册的全局守卫(使用上面示例中的 useGlobalGuards())不能注入依赖项,因为这是在任何模块的上下文之外完成的。

这是他们的样品?

// app.module.js
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: RolesGuard,
    },
  ],
})
export class ApplicationModule {}
Run Code Online (Sandbox Code Playgroud)

它有效。现在我可以使用防护全局而不会出现依赖错误。


Zso*_*oca 5

也许为时已晚,但我遇到了同样的问题并找到了解决方案。也许有更好的,但它对我来说工作正常:

将 KeysModule 定义为全局模块,您可以在 nestjs 文档中查看如何操作:https ://docs.nestjs.com/modules

之后你可以这样做:

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

@Injectable()
export class ApiGuard implements CanActivate {

constructor(
@Inject('KeyService')
private readonly ks
) {}

const key = await this.ks.findKey();

"YOUR_CODE_HERE..."

}
Run Code Online (Sandbox Code Playgroud)

希望它对您或将来会坚持此问题的人有所帮助。