Nestjs シリーズ - ガード


序章



警備員!名前が示すように、パーミッションなしで何かにアクセスできないように保護します.ガードは、基礎となるフレームワークによって提供されるか、開発者によってカスタム コード化されるかに関係なく、ほとんどのバックエンド フレームワークで共通の概念です. Nestjs を使用すると、許可されていないユーザーや認証されていないユーザーから API を簡単に保護および保護できます.

パイプやフィルターと同様に、nestjs のガードは @Injectable() デコレーターで装飾されています.使用するすべてのガードは、CanActivate インターフェイスを実装する必要があります. CanActivate インターフェイス プロパティを使用すると、開発者は独自のガード ロジックを簡単にカスタム コーディングできます.

ルートを保護するミドルウェアとガードの違いを理解しましょう.ミドルウェアは、その後に何が実行されるかをまったく認識していません.一方、ガードは ExecutionContext インスタンスにアクセスできるため、その直後に何が実行されるかを認識しています.これらはフィルターやパイプによく似ており、要求と応答のサイクルで正しいタイミングで正しいロジックを挿入できます.このプロパティミドルウェアがダムであることを証明します.

ガードは、各ミドルウェアの後、パイプまたはインターセプターの前に実行されます.

例で何が言われているかを理解しましょう (以下のコード スニペットは、nestjs の公式ドキュメントから取得したものです).

@Injectable()
export class AuthGuard implements CanActivate{
canActivate(context:ExecutionContext):boolean|Promise<boolean>|Observable<boolean>{
   const request=context.switchToHttpRequest().getRequest();
   //code to validate the request object for roles and 
   //restrictions
}
}


スニペットを見ると、ほとんどの人は ExecutioContext の使用法を理解しているはずですが、websocket 接続コンテキストまたは gql 実行コンテキストを取得したい場合はどうでしょうか. ExecutionContext はそれらすべてをカバーします.必要なコンテキストに切り替えて、ロジックを操作するだけです. ExecutionContext クラスは ArgumentsHost を拡張し、コンテキストを切り替えるための適切なメソッドを提供します.これはこの記事の範囲外であるため、必要に応じて公式ドキュメントをチェックアウトできます.

これらの警備員を拘束することについて話しましょう.パイプ、フィルター、インターセプターと同様に、ガードはコントローラー スコープ、メソッド スコープ、またはグローバル スコープにすることができます.以下では、@UseGuards() デコレーターを使用して、コントローラー スコープ レベルでガードを使用します.

@Controller('pokemons')
@UseGuards(AuthGuard)
export class PokemonController{}


Guard のクラス名をデコレータに渡しました.インスタンスを Guard に渡すことも、インスタンスやタイプのリストを渡すこともできます.

役割の設定



役割は、要求と応答のサイクルを完了できるようにコントローラーのメソッドに指示する方法です.特定の役割がエンドポイントへのアクセスを許可されていない場合、要求と応答のサイクルはここで終了し、通常は 401 の無許可のエラー メッセージが返されます. HTTP ステータスコード.私たちの警備員は非常に賢いですが、どのロールがどのエンドポイントに許可されているかを知りません.ここで、カスタム メタデータが活躍します.カスタム メタデータを使用すると、以下に示すように、ロールに基づいてエンドポイントを分離できます.

@Post("/updateAccess") 
@SetMetadata('roles',['admin','superadmin'])
async updateReadWriteAccessofUser(@Body() inputDto:any):Promise<boolean>{
  this.adminService(inputDto);
}


これで、ロールを updateReadWriteAccessOfUser メソッドに割り当てました.このエンドポイント「/updateAccess」にアクセスできるのは、「admin」ロールと「superadmin」ロールを持つユーザーのみです.この概念を理解するにはこれで十分ですが、コントローラー メソッドに直接ロールを割り当てることはお勧めできません.代わりに、独自のデコレータをコーディングして使用できます.これは、DRY の堅固な原則に従うようにコード化されています.

import {SetMetadata} from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);



これで、必要に応じてこのデコレータを再利用できます.

@Post("/updateAccess") 
@Roles(["admin","superadmin"])
async updateReadWriteAccessofUser(@Body() inputDto:any):Promise<boolean>{
  this.adminService(inputDto);
}


ここで、ロールとガードの概念を組み合わせて、エンドポイントを不正なリクエストから保護します.

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

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return verifyRoles(roles, user.roles);
  }
}

export function Roles(...roles: string[]) {
    return applyDecorators(
        SetMetadata('roles', roles),
        UseGuards(RolesGuard),
    );
}




Reflector ヘルパー クラスは、コントローラー メソッドのロールにアクセスするために、nestjs フレームワークによって提供されます.ロールと現在のリクエストのロールを検証し、検証に基づいてブール値を返します. 2 番目のコード スニペットでは、この RolesGuard を applyDecorators のパラメーターとして使用します. applyDecorators メソッドは、複数のデコレータを組み合わせて実行します.

ガードによってスローされたすべての例外は、例外レイヤー (グローバル例外フィルターおよび現在のコンテキストに適用されるすべての例外フィルター) によって処理されます.