web-dev-qa-db-ja.com

Nest.JSのガードにサービスを注入する

APIキーを追加または削除するために使用できるKeysModuleがあります。一部のルートを不正アクセスから保護するには、これらのキーが必要です。これらのルートを保護するために、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;
  }
}

そして、私はそれをルートで使用します:

 @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';
 }

ここで、ksは、キーが正しいかどうかを確認するために使用されるKeyServiceです。この解決策は機能しますが、愚かです。このガードを使用するすべての場所にコードのいくつかの行をコピーして貼り付ける必要があります(つまり、ルート内の行を意味します)。

すべてのロジックをApiGuardに移動しようとしましたが、KeyServiceをApiGuardクラスに挿入できないというエラーが発生しました。説明すると、KeysModuleのプロバイダーにKeyServiceがありますが、ApiGuardはグローバルに使用されています。

あなたはそれを行う方法について何か考えがありますか?

5
Greggy

サービスをガードに注入します。グローバルモジュールを作成できます。

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

@Global()
@Module({
    providers: [ KeyService ],
    exports: [KeyService]
})
export class ApiModule {}

次に、このようにサービスをガードに注入します

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

これで問題は解決できますが、別の問題があります。サービスに何かを注入したいのですが、次のエラーが発生しました。

NestはAuthGuardの依存関係を解決できません(?、+)。インデックス[0]の引数が現在のコンテキストで使用可能であることを確認してください。

そして、これが私の解決策です:

KeyServiceに他の依存関係を挿入するには nestjs docs say。

モジュールの外部から登録されたグローバルガード(上記の例のように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 {}

これで、依存関係エラーなしでガードグローバルを使用できます。

1
Jinni

手遅れかもしれませんが、同じ問題を実行して解決策を見つけました。より良いものがあるかもしれませんが、それは私にとって適切に機能しています:

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..."

}

それがあなたや将来これに固執する誰かの助けになることを願っています。

2
Zsoca

Injectableで注釈が付けられた他のオブジェクトと同様に、ガードにサービスを挿入できます。 ApiGuardにKeyServiceが必要な場合は、次の2つの選択肢があります。

  • KeysModuleをインポートするモジュールにApiGuardを追加します。次に、作成したモジュールをインポートして、ApiGuardをグローバルに使用します
  • KeysModuleにApiGuardを追加し、エクスポートします。
0
quen2404