打印

Go 每日一库

[复制链接]
336|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2020-11-3 15:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
go, AD, TE, ev, AN
本帖最后由 keer_zu 于 2020-11-3 16:45 编辑

https://www.zhihu.com/column/c_1298647071763718144
https://zhuanlan.zhihu.com/p/148353743

RBAC 模型ACL模型在用户和资源都比较少的情况下没什么问题,但是用户和资源量一大,ACL就会变得异常繁琐。想象一下,每次新增一个用户,都要把他需要的权限重新设置一遍是多么地痛苦。RBAC(role-based-access-control)模型通过引入角色(role)这个中间层来解决这个问题。每个用户都属于一个角色,例如开发者、管理员、运维等,每个角色都有其特定的权限,权限的增加和删除都通过角色来进行。这样新增一个用户时,我们只需要给他指派一个角色,他就能拥有该角色的所有权限。修改角色的权限时,属于这个角色的用户权限就会相应的修改。
在casbin中使用RBAC模型需要在模型文件中添加role_definition模块:
[role_definition]g = _, _[matchers]m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
g = _,_定义了用户——角色,角色——角色的映射关系,前者是后者的成员,拥有后者的权限。然后在匹配器中,我们不需要判断r.sub与p.sub完全相等,只需要使用g(r.sub, p.sub)来判断请求主体r.sub是否属于p.sub这个角色即可。最后我们修改策略文件添加用户——角色定义:
p, admin, data, readp, admin, data, writep, developer, data, readg, dajun, adming, lizi, developer
上面的policy.csv文件规定了,dajun属于admin管理员,lizi属于developer开发者,使用g来定义这层关系。另外admin对数据data用read和write权限,而developer对数据data只有read权限。
package mainimport (  "fmt"  "log"  "github.com/casbin/casbin/v2")func check(e *casbin.Enforcer, sub, obj, act string) {  ok, _ := e.Enforce(sub, obj, act)  if ok {    fmt.Printf("%s CAN %s %s\n", sub, act, obj)  } else {    fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)  }}func main() {  e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")  if err != nil {    log.Fatalf("NewEnforecer failed:%v\n", err)  }  check(e, "dajun", "data", "read")  check(e, "dajun", "data", "write")  check(e, "lizi", "data", "read")  check(e, "lizi", "data", "write")}
很显然lizi所属角色没有write权限:
dajun CAN read datadajun CAN write datalizi CAN read datalizi CANNOT write data
多个RBACcasbin支持同时存在多个RBAC系统,即用户和资源都有角色:
[role_definition]g=_,_g2=_,_[matchers]m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
上面的模型文件定义了两个RBAC系统g和g2,我们在匹配器中使用g(r.sub, p.sub)判断请求主体属于特定组,g2(r.obj, p.obj)判断请求资源属于特定组,且操作一致即可放行。
策略文件:
p, admin, prod, readp, admin, prod, writep, admin, dev, readp, admin, dev, writep, developer, dev, readp, developer, dev, writep, developer, prod, readg, dajun, adming, lizi, developerg2, prod.data, prodg2, dev.data, dev
先看角色关系,即最后 4 行,dajun属于admin角色,lizi属于developer角色,prod.data属于生产资源prod角色,dev.data属于开发资源dev角色。admin角色拥有对prod和dev类资源的读写权限,developer只能拥有对dev的读写权限和prod的读权限。
check(e, "dajun", "prod.data", "read")check(e, "dajun", "prod.data", "write")check(e, "lizi", "dev.data", "read")check(e, "lizi", "dev.data", "write")check(e, "lizi", "prod.data", "write")
第一个函数中e.Enforce()方法在实际执行的时候先获取dajun所属角色admin,再获取prod.data所属角色prod,根据文件中第一行p, admin, prod, read允许请求。最后一个函数中lizi属于角色developer,而prod.data属于角色prod,所有策略都不允许,故该请求被拒绝:
dajun CAN read prod.datadajun CAN write prod.datalizi CAN read dev.datalizi CAN write dev.datalizi CANNOT write prod.data
多层角色casbin还能为角色定义所属角色,从而实现多层角色关系,这种权限关系是可以传递的。例如dajun属于高级开发者senior,seinor属于开发者,那么dajun也属于开发者,拥有开发者的所有权限。我们可以定义开发者共有的权限,然后额外为senior定义一些特殊的权限。
模型文件不用修改,策略文件改动如下:
p, senior, data, writep, developer, data, readg, dajun, seniorg, senior, developerg, lizi, developer
上面policy.csv文件定义了高级开发者senior对数据data有write权限,普通开发者developer对数据只有read权限。同时senior也是developer,所以senior也继承其read权限。dajun属于senior,所以dajun对data有read和write权限,而lizi只属于developer,对数据data只有read权限。
check(e, "dajun", "data", "read")check(e, "dajun", "data", "write")check(e, "lizi", "data", "read")check(e, "lizi", "data", "write")
RBAC domain在casbin中,角色可以是全局的,也可以是特定domain(领域)或tenant(租户),可以简单理解为。例如dajun在组tenant1中是管理员,拥有比较高的权限,在tenant2可能只是个弟弟。
使用RBAC domain需要对模型文件做以下修改:
[request_definition]r = sub, dom, obj, act[policy_definition]p = sub, dom, obj, act[role_definition]g = _,_,_[matchers]m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.obj
g=_,_,_表示前者在后者中拥有中间定义的角色,在匹配器中使用g要带上dom。
p, admin, tenant1, data1, readp, admin, tenant2, data2, readg, dajun, admin, tenant1g, dajun, developer, tenant2
在tenant1中,只有admin可以读取数据data1。在tenant2中,只有admin可以读取数据data2。dajun在tenant1中是admin,但是在tenant2中不是。
func check(e *casbin.Enforcer, sub, domain, obj, act string) {  ok, _ := e.Enforce(sub, domain, obj, act)  if ok {    fmt.Printf("%s CAN %s %s in %s\n", sub, act, obj, domain)  } else {    fmt.Printf("%s CANNOT %s %s in %s\n", sub, act, obj, domain)  }}func main() {  e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")  if err != nil {    log.Fatalf("NewEnforecer failed:%v\n", err)  }  check(e, "dajun", "tenant1", "data1", "read")  check(e, "dajun", "tenant2", "data2", "read")}
结果不出意料:
dajun CAN read data1 in tenant1

dajun CANNOT read data2 in tenant2




使用特权

评论回复

相关帖子

沙发
keer_zu|  楼主 | 2020-11-3 17:40 | 只看该作者
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1349

主题

12426

帖子

53

粉丝