簡介
https://docs.nestjs.cn/9/guards
守衛是一個使用 @Injectable()
裝飾器的類。 守衛應該實現 CanActivate
接口。
守衛有一個單獨的責任。它們根據運行時出現的某些條件(例如權限,角色,訪問控制列表等)來確定給定的請求是否由路由處理程序處理。這通常稱爲授權。在傳統的 Express
應用程序中,通常由中間件處理授權(以及認證)。中間件是身份驗證的良好選擇,因爲諸如 token
驗證或添加屬性到 request
對象上與特定路由(及其元數據)沒有強關聯。
中間件不知道調用 next()
函數後會執行哪個處理程序。另一方面,守衛可以訪問 ExecutionContext
實例,因此確切地知道接下來要執行什麼。它們的設計與異常過濾器、管道和攔截器非常相似,目的是讓您在請求/響應週期的正確位置插入處理邏輯,並以聲明的方式進行插入。這有助於保持代碼的簡潔和聲明性。
守衛在每個中間件之後執行,但在任何攔截器或管道之前執行。
創建一個守衛
nest g gu [name]
例:
nest g gu role
注意:上面的命令在那個目錄下執行,就會在那個目錄下創建
內容
守衛要求實現函數 給定參數context執行上下文 要求返回布爾值
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class RoleGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return true;
}
}
Controller 使用守衛
我們在守衛中打印一句
console.log('假設已經通過了守衛規則的校驗。。。。。。。。')
在 p 模塊中使用
主要代碼
import { RoleGuard } from '../common/role/role.guard';
@UseGuards(RoleGuard)
測試
http://localhost:3000/p/7f145099-e9c7-47d9-99fb-a0a3f9a39bd7?id=1314
全局守衛
如果要註冊全局守衛,只需要在 main.ts 中註冊即可
創建守衛
nest g gu global
守衛內容
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class GlobalGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
console.log('這裏是全局守衛。。。。。。。。。');
return true;
}
}
main.ts 中註冊
// 註冊全局守衛
app.useGlobalGuards(new GlobalGuard)
測試結果
針對角色控制守衛
注意這裏只能裝飾 controller 的方法,不能全局
SetMetadata
裝飾器
第一個參數爲key,第二個參數自定義我們的例子是數組存放的權限
controller 中使用
@SetMetadata('role', ['admin'])
角色守衛內容
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core'
import type { Request } from 'express'
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private Reflector: Reflector) { }
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
// guard 使用 Reflector 反射讀取 setMetaData的值
const admin = this.Reflector.get<string[]>('role', context.getHandler())
const request = context.switchToHttp().getRequest<Request>()
// 去做判斷這邊例子是從url 判斷有沒有admin權限
if (admin.includes(request.query.role as string)) {
console.log('返回true');
return true;
}else{
console.log('返回false');
return false
}
}
}
測試
正確的
http://localhost:3000/p?role=admin
錯誤的
http://localhost:3000/p?role=test