接 Nestjs RBAC 權限控制管理實踐 (一)node
上回分析了 node-casbin 模塊, Casbin 主要是提供了多種的權限控制策略, 支持 ACL, RBAC, ABAC, RESTful 以及複雜的拒絕覆蓋, 權限優先等級等。 不得不說 Casbin 功能強大,不過對於個人項目需求,直接用起來,看似又比較複雜了。 由於我這個項目主要是用RESTful API, 因此借鑑了 accesscontrol 和 casbin 的 RESTful 的控制模式簡化成我要的版本,具體以下:git
上回咱們看官網的方式是,使用 @RolesGuard 和 @Roles 組合的方式, 使用 @RolesGuard 去守護, @Roles 則去標記哪一個角色能夠經過。github
咱們回顧下代碼 @RolesGuard 搭檔 @Roles數據庫
@Controller('cats')
@UseGuards(RolesGuard)
@UseInterceptors(LoggingInterceptor, TransformInterceptor)
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Post()
@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
}
複製代碼
因爲注意到經常使用的 AuthGuard('jwt') 是又參數的, 可是 RolesGuard 是沒有參數的, 也沒法帶上參數, 因此特意去翻了下 AuthGuard 的源代碼. auth.guard.tsbash
export const AuthGuard: (type?: string) => Type<IAuthGuard> = memoize(
createAuthGuard
);
function createAuthGuard(type?: string): Type<CanActivate> {
class MixinAuthGuard<TUser = any> implements CanActivate {
...
}
}
複製代碼
對比 AuthGuard 發現其是比較特殊的函數方式返回一個 CanActivate 的實現類, 這個實現比較複雜,同時也失去了依賴注入的能力。 而且因爲項目需求是由界去配置權限和 API 的關聯關係的,因此這裏並不能直接用角色去關聯API。 還有另一個緣由是 RESTFul 的 API 能夠採用約定的規則來匹配權限,因此並沒必要要每一個 API 去打標記, 匹配形式爲 :async
{
GET: 'read', // 讀取
POST: 'create', // 建立
PUT: 'update', // 更新
DELETE: 'delete', // 刪除
}
複製代碼
通過上面的處理, 咱們在控制器上能夠解放出來了,咱們只要一個 @RolesGuard, 並不要 @Roles 來配合了。函數
但因爲 @RolesGuard 沒法傳遞控制器參數, 因此咱們只能另尋辦法了, 想到 @RolesGuard 能獲取到 @Roles 裏註解參數, 咱們是否是能從 @Controller 裏得到參數呢? 這樣咱們就能定位當前的請求資源了,因而有了下面的代碼: 最終代碼post
async canActivate(context: ExecutionContext): Promise<boolean> {
const roles = this.reflector.get<string[]>(
'roles',
context.getHandler(),
); // 這裏咱們能從 context.getHandler() 裏獲得 roles;
/** 那麼咱們也就能從 context.getClass() 裏獲得 @Controller 裏的註解參數,
固然,咱們也能從 request.url 裏分析獲得,可是控制器的註解有時候可能寫的複雜 如 abc/efg 咱們就不知道怎麼截斷了。
**/
const ctrl = this.reflector.get<string>('path', context.getClass());
...
}
複製代碼
我寫了一個 API 的描述文件ui
const actions = {
create: '建立',
read: '讀取',
update: '更新',
delete: '刪除',
};
export interface GrantNode {
name: string;
actions: {
[k: string]: string;
create?: string;
read?: string;
update?: string;
delete?: string;
};
}
export const grants: {
[key: string]: GrantNode;
} = {
dict: {
name: '字典',
actions,
},
group: {
name: '用戶組',
actions,
},
log: {
name: '日誌',
actions,
},
menu: {
name: '菜單',
actions,
},
notice: {
name: '通知',
actions,
},
role: {
name: '角色',
actions,
},
setting: {
name: '設置',
actions,
},
user: {
name: '用戶',
actions,
},
};
複製代碼
腳本在這裏, 插入到菜單, 以後就能夠選配到菜單的葉子節點來關聯權限了。this
最終能這麼配置了:
代碼詳細請看 nestx. 有不理解的請加羣交流 QQ羣:489719517 , 支持請加星關注謝謝!