NestJs Guard
NestJs Guard
サンプルコードはGithubにあります.)
Goal
NestJs
からGuardの使い方を知る. - ExcutionContext
- custom metadata
NestJs
Guardを作成します.Guardとは?
ガードは、
@Injectable()
デコーダを用いて、CanActivate
インターフェースを実装するクラスである.@Injectable()
を使用する理由は、インスタンスではなくタイプを渡すためであり、インスタンス化の責任は、フレームワークに残して依存性を持たせることである.(new
を使用してインスタンスを追加することもでき、以下に詳細に説明する)防御は単一の責任、特定の状況(権限、役割、ACLS...)これにより、与えられた要求は、ルーティングハンドルによって処理されるか否かが決定される.
Express
では主にミドルウェアを用いて処理される.ミドルウェアは主に認証関連の作業に用いられ、
NestJs
で認可された作業は防御によって完了する.公式ファイルによると、ミドルウェアは
next()
を呼び出した後、どのルーティングハンドルが実行されるか分からない.しかしながら、ExcutionContext
を使用することができるので、次のステップで実行されるルーティングハンドルを正確に知ることができる.HINTGuards are executed after each middleware, but before any interceptor or pipe.(保護はミドルウェアの後に実行され、インタフェースとパイプの前に実行されます.)
CanActiveインタフェース
CanActive
インタフェースの構成は次のとおりです.export interface CanActivate {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean>;
}
パラメータとして実行コンテキスト(ExecutionContext)を受け入れるcanActivate
という方法がある.実行コンテキスト
canActivate
メソッドパラメータとしての実行コンテキストは、ArgumentHost
を継承する.export interface ArgumentsHost {
getArgs<T extends Array<any> = any[]>(): T;
getArgByIndex<T = any>(index: number): T;
switchToRpc(): RpcArgumentsHost;
switchToHttp(): HttpArgumentsHost;
switchToWs(): WsArgumentsHost;
getType<TContext extends string = ContextType>(): TContext;
}
export interface ExecutionContext extends ArgumentsHost {
getClass<T = any>(): Type<T>;
getHandler(): Function;
}
ArgumentsHost
は、前のフィルタを使用しているときに見られるはずです.ExecutionContext
はArgumentsHost
を継承するので、switch
は、各通信プロトコルに適したRequest, Response, next()
法によって得ることができる.ここで重要な点は
ExecutionContext
が有する方法である.getClass
は、クライアントへのアクセスを要求するときに処理可能なルーティングハンドル付きコントローラの情報を有し、getHandler
は、クライアントからの要求を処理するルーティングハンドルの情報を有する.したがって、ミドルウェアとは異なり、その後実行されるコントローラまたはルーティングハンドルの情報を知ることができます.
カスタム保護の作成(ロールベース)
上に書いた内容で、Custom Guardを簡単に作成できます.
@Injectable()
export class RoleGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
return true
}
}
上記のカスタムガードを適用する方法はパイプ適用層とあまり変わらない.핸들러-레벨
に適用してサンプルコードを記述します.export class AppController {
constructor(private readonly appService: AppService) { }
@Get()
@UseGuards(RoleGuard)
getHello(): string {
return this.appService.getHello();
}
}
前述したように、@UseGuards
デコーダを使用して防御することができ、現在、エンドポイントに送信された要求はRoleGuard
からtrue
に戻り、何も起こらない.でも!
false
の値を返すと、クライアントは次のメッセージを受信します.{
"statusCode": 403,
"message": "Forbidden resource",
"error": "Forbidden"
}
上記のメッセージをクライアントに渡すのではなくカスタマイズする場合は、認証に失敗した場合、throw
で新しい例外を処理し、例外フィルタで応答を操作できます.上のように護衛を作ることができますが、公式文書によると、これはスマートな方法ではありません.ガードレールの最大の利点は、上述したように
ExecutionContext
を使用できることである.どのルーティングハンドルまたはコントローラが使用されているかを知ることができるので、要求されたエンドポイントが
Role
に合致することを保証することができる.このとき出現する概念はcustom metadata
である.custom metadata
custom metadata
は、@SetMetadata()
を使用して、コントローラまたはルータハンドルにメタデータを定義することができる.@Get()
@SetMetadata('role', 'admin')
@UseGuards(RoleGuard)
getHello(): string {
return this.appService.getHello();
}
以上のように、@SetMetadata()
を用いて、role
というメタデータをadmin
のキー値として定義し、getHello
のルーティングハンドルを付与する.しかし、公式文書によると、ルータHandlerに
@SetMetadata()
を直接使うのはよくない方法だ.そこで、カスタムデータムコーディネータを作成して指定します.// custom decorator
export const Roles = (role: string) => SetMetadata('role', role);
// route handler
@Get()
@Role('admin')
@UseGuards(RoleGuard)
getHello(): string {
return this.appService.getHello();
}
Role
は、CustomDecoratorによって読み取り可能なコードとして付与され、強制的なタイプとすることができる.Reflectorを使用したメタデータの使用
上記の概念をすべて加算すると、
@SetMetadata()
(or上に作成されたcustomベンチマークコーディネータ)を用いてmetadataをルーティングハンドルに付与し、ExecutionContext
を用いて以降実行されるルーティングハンドルの情報をガードで知ることができる.では、ルータハンドルのメタデータをどのように取得しますか?
NestJs
では、Reflector
を使用してメタデータにアクセスできます.Reflector
は、生成者においてDI
を得ることができる.@Injectable()
export class RoleGuard implements CanActivate {
constructor(private readonly reflector: Reflector) { }
canActivate(context: ExecutionContext,): boolean {
const role = this.reflector.get<string>('role', context.getHandler());
// do something
}
}
export declare class Reflector {
//...
get<TResult = any, TKey = any>(metadataKey: TKey, target: Type<any> | Function): TResult;
//...
}
パラメータ、第1の受信キー、第2の受信タイプ、またはReflector
として、get
によって提供されるFunction
を使用してメタデータをインポートすることができる.このとき、タイプまたはFunction
に関する情報をExecutionContext
から取得することができる.Reference
https://docs.nestjs.com/guards#guards
https://wikidocs.net/158626
Reference
この問題について(NestJs Guard), 我々は、より多くの情報をここで見つけました https://velog.io/@dev_leewoooo/NestJs-Guardテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol