接 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 , 支持请加星关注谢谢!