支持多种访问控制模型,如ACL/RBAC/ABAC
等,可以实现灵活的访问权限控制
casbin
将访问控制模型抽象到一个基于PERM(Policy,Effect,Request,Matchers)元模型的配置文件中
测试或者是说规则的定义,定义了具体的规则
对访问请求的抽象,与e.Enforce()
的参数一一对应
匹配器,请求与每个policy
一一匹配,生成多个匹配结果
对结果进行汇总,决定请求是允许还是拒绝
access-control-list 访问控制列表
显示定义了每个主体对每个资源的权限情况,未定义的就没有权限,还可以加入超级管理员,只需要修改匹配器即可
model.conf
[request_definition] r = sub,obj,act [policy_definition] p = sub,obj,act [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act [policy_effect] e = some(where (p.eft == allow))
policy.csv
p,dajun,data1,read p,lizi,data2,write
ACL用户量一大就不得了,总不能每个用户都添加对应的策略文件吧
RBAC(role-based-access-control)通过引入角色来解决问题,给角色设置权限,而用户是属于角色,新增用户只需要赋予权限就可以了
model.conf
[role_definition] g = _, _ [matchers] m = g(r.sub,p.sub) && r.obj == p.obj && r.act == p.act
policy.csv
p,admin,data,read p,admin,data,write p,developer,data,read g,dajun,admin g,lizi,developer
用户和资源都有角色
[role_definition] g=_,_ g2=_,_ [matchers] m = g(r.sub,p.sub) && g2(r.obj,p.obj) && r.act == p.act
p, admin, prod, read p, admin, prod, write p, admin, dev, read p, admin, dev, write p, developer, dev, read p, developer, dev, write p, developer, prod, read g, dajun, admin g, lizi, developer g2, prod.data, prod g2, dev.data, dev
为角色定义所属角色,实现多层角色关系,例如高级开发者senior也属于开发者,拥有开发者的所有权限,然后再对senior定义自己所特有的权限
只需要修改对应的策略文件,将角色作为一个普通用户去赋予对应的父权限即可,这样就可以继承父角色的权限
角色可以是全局的,也可以是特定domain(领域)
或tenant(租户)
,即分组
模型文件 [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
前面的模型对于相对静态的权限管理比较有用,但是对于特殊、动态的需求就不合适了
例如不同时间段对数据实现不同的权限控制,就适合用ABAC模型完成
[request_definition] r = sub,obj,act [policy_definition] p = sub,onj,act [matchers] m = r.sub.Hour >= 9 && r.sub.Hour < 18 || r.sub.Name == r.obj.Owner [policy_effect] e = some(where (p.left == allow))
存储在文件里是十分不方便的,所以casbin实现在代码中动态初始化模型
例如字符串,或者调用方法添加,但是不常用
一般情况下,casbin支持第三方的存储方法,包括Mysql/MongoDB/Redis/Etcd
等,还可以实现自己的存储
sqlCREATE DATABASE IF NOT EXISTS casbin; USE casbin; CREATE TABLE IF NOT EXISTS casbin_rule ( p_type VARCHAR(100) NOT NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4 VARCHAR(100), v5 VARCHAR(100) ); INSERT INTO casbin_rule VALUES ('p', 'dajun', 'data1', 'read', '', '', ''), ('p', 'lizi', 'data2', 'write', '', '', '');
golangpackage main import ( "fmt" "github.com/casbin/casbin/v2" gormadapter "github.com/casbin/gorm-adapter/v2" _ "github.com/go-sql-driver/mysql" ) 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() { a, _ := gormadapter.NewAdapter("mysql", "root:12345@tcp(127.0.0.1:3306)/") e, _ := casbin.NewEnforcer("./model.conf", a) check(e, "dajun", "data1", "read") check(e, "lizi", "data2", "write") check(e, "dajun", "data1", "write") check(e, "dajun", "data2", "read") }
本文作者:Malyue
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!