san*_*oco 7 javascript roles rbac typescript nestjs
我们有一个应该实现 rbac 的 Nest 应用程序。我根据守卫文档为其添加了一个基本的守卫和装饰器: https: //docs.nestjs.com/guards。问题:这仅允许静态角色。
我们的目标:在我们的例子中,我们有一个Contract实体。仅当合同的承包商 ( <User>) 或承包商的主管 ( <User>) 尝试访问该合同时,才应加载该合同。我不想实施诸如此类的事情,if (contract.contractor.id === user.id)因为我们有很多不同的情况,随着时间的推移,这会让事情变得一团糟。
它看起来像下面这样:
@Get()
@Roles(ROLES.ADMIN, ROLES.CONTRACTOR, ROLES.SUPERVISOR)
getContractById(...): Contract {
return this.contractService.findById(...);
}
Run Code Online (Sandbox Code Playgroud)
当然,ROLES.SUPERVISOR只是一个字符串,然后与用户的静态角色进行匹配。所以问题是:如何使用动态角色来实现类似的功能,例如主管角色,它仅在某些项目的上下文中是动态的。
您需要首先从概念上解决这个问题。
我认为您应该编写一个能够计算特定合约的特定用户是什么的方法。
超级简单的例子:
getUserRoleForContract(user: User, contract: Contract): ROLES {
// your logic goes here
if (contract.contractor.id === user.id) {
return ROLES.CONTRACTOR;
} else if (...) {...}
return null;
}
Run Code Online (Sandbox Code Playgroud)
在你的守卫中,从上下文中,你知道哪个用户和合约请求是关于哪个用户和合约请求,利用此方法获取 ROLE,然后将结果与请求的角色进行比较。
现在,您明确表示您不想使用这种方法(检查用户和合同的每个组合)。
我认为您getUserRoleForContract现在应该根据您对实体关系的了解来改进此方法的实现。
从你的问题中,我看到承包商和主管。此拟合基于该(有限)信息:
getUserRoleForContract(user: User, contract: Contract): ROLES {
const allAvailableRoles = [ROLES.CONTRACTOR, ROLES.SUPERVISOR];
for (let role of allAvailableRoles) {
if (contract[role.toLowerCase()].id === user.id) {
return role;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
这将在假设合约上的每个用户关系实际上是 ManyToOne 且名称与 ROLE 名称相同但小写的情况下起作用(并且假设 ROLES 枚举值是相同的大写字符串)。
总而言之,我希望这对您有所帮助并回答问题。
EDIT2:我修复了 this 指向的 URL。
我刚刚将答案放在这里:What would be the best way to create an isAuthor Guard for Nestjs? 。它涵盖了 Nest.js 中 RBAC 的更大解决方案(包括此场景)。