三万里求道,终归朴素田园
爱,就是我有要给你身心快乐的使命感,如果爱是2个人之间的事情,那就是2个人一起寻找快乐的过程;
爱,就是我有让自己身心快乐的使命感,如果我热爱某件事情
Casbin简介
Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。目前这个框架的生态发展很好。提供了各种语言的类库,比如Go,Java,Python,Rust。自定义的权限模型语言,以及模型编辑器。在各种语言中,golang的支持是最全的。
有哪些大厂在用Casbin呢?IBM,Intel,微软 ,360
有哪些项目在用Casbin呢?Docker,k8s,Zenpress(go开发的CMS系统)
Casbin的核心思想是配置就是一切。也就是它实现权限控制的方法是通过定义配置文件。因此官网专门有一个editor来编写配置文件。在我们常见的web系统都会存在一定程度的权限控制,比如管理员具有所有权限,普通角色则具有一小部分自己的权限。权限因为资源的存在而存在。在云计算时代,更多的资源被放在网络上作为商品,则更需要权限控制。
尽管权限控制是如此频繁,却没有出现一个比较通用的框架解决方法。因为比如在java里面,已经出现了shiro,spring security等权限框架。但是到其他语言这些框架则不能使用。不具有跨语言的特点。
基于以上的问题,配置就是一切的思想就解决了这样的痛点。
Casbin核心概念
前面说到Casbin通过配置文件控制权限。它有2个配置文件,一个是model.conf,一个是policy.csv。model.conf里面定义的是权限控制的信息,policy.csv定义了具体的用户的权限信息。其实权限就是问:某个用户,对某个资源,是否可以进行某种操作。
简单使用
import "github.com/casbin/casbin/v2"
e, err := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")
sub := "mee" // the user that wants to access a resource.
obj := "data" // the resource that is going to be accessed.
act := "create" // the operation that the user performs on the resource.
// 查看mee是否对data1z这个资源有create权限
ok, err := e.Enforce(sub, obj, act)
if err != nil {
// handle err
}
if ok == true {
// permit alice to create data
} else {
// deny the request, show an error
}
基于角色的权限控制(RBAC)
RBAC全称是role-based access control。这是很多业务系统使用的权限控制方案。它在用户和权限之间引入了角色的概念。让用户拥有某个角色或多个角色,然后给角色赋予某些权限,查看一个用户有没有权限是先通过查看他是什么角色来确定。可见角色是用来管理权限的。用户和角色是多对多的关系,角色和权限也是多对多的关系。
比如一般的业务系统都有管理员和普通用户这样的角色。
基于RBAC在具体的业务设计会有对权限的更细节的控制。比如当一个用户有2个角色的时候,会对这样多角色用户进行某种约束,比如这个用户进入系统需要选择他有的角色里面的一个角色。这种情况叫做动态角色分配。
还有一种约束是只有更高权限的人才可以给更低权限的用户分配权限。比如在刚进入公司的时候,gitlab的项目需要分配给新人,就需要具有高权限的人来分配,而不能自己给自己分配项目。
RBAC适合的场景:中小型的企业,角色和权限的关系比较简单的情况。不适合用在大型组织,角色和权限关系很复杂,权限粒度很细的业务。
基于属性的权限控制(ABAC)
ABAC全称 attribute-based access controll。这种是从属性的角度控制权限,其中属性用户属性,环境属性,资源属性。
用户属性:比如名称,角色,组织,安全许可等
环境属性:比如访问的时间,数据的位置
资源属性:比如文件名,创建时间,资源拥有者
比如开发人员只能在上班时间访问服务器资源,那么权限系统基于ABAC就会做到:当有人访问服务器资源的时候检查当前用户是否是开发人员,如果是,会检查当前时间是否是上班时间,如果不是也会拒绝访问。
ABAC适用场景:在大型组织/项目中,对权限控制比较灵活和粒度比较细的情况。但是对权限控制的构建比较复杂。
model.conf文件怎么写
model.conf 至少包含四个部分:[request_definition], [policy_definition], [policy_effect], [matchers]。如果 model 使用 RBAC, 还需要添加[role_definition]部分。
文件的注释以#开头。
Request定义
[request_definition]
r = sub, obj, act
sub:访问实体 (Subject)
obj:访问资源 (Object)
act:访问方法 (Action)。
Policy定义
[policy_definition]
#定义有哪些 policy 包含哪些部分
p = sub, obj, act
p2 = sub, act
#每个policy对应的具体描述 比如sub是什么 obj是s很么
p, alice, data1, read
p2, bob, write-all-objects
绑定关系如下
(alice, data1, read) -> (p.sub, p.obj, p.act)
(bob, write-all-objects) -> (p2.sub, p2.act)
Policy effect定义
[policy\_effect] 是策略效果的定义。它确定如果多项政策规则与请求相符,是否应批准访问请求。例如,一项规则允许,另一项规则则加以拒绝。
[policy_effect]
# some 表示存在一个匹配的策略 p.eft是p.effect的简写 表示效果 allow
#表示允许
e = some(where (p.eft == allow))
匹配器
[matchers] 是策略匹配程序的定义。匹配程序是表达式。它定义了如何根据请求评估策略规则。实际上定义了Request和Policy的对应关系
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
下面给一个完整的RBAC的栗子
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
# g是一个RBAC系统 ,前后是继承关系 表示,前者具有后者的权限
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
# 在请求中应该在policy中包含sub角色
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
rbac_policy.csv栗子:定义在model.conf里面的policy对应的具体的权限
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
# alice 具有data2_admin的权限
g, alice, data2_admin
注意:如果在定义policy.csv的时候,某一块出现了英文逗号,需要用双引号,以便和文件里面用英文逗号区别不同块不冲突。
p, alice, "data1,data2", read --correct
p, alice, data1,data2, read --incorrect
policy.csv这类 .csv一般是数据库数据导出文件的格式。
在正式的业务系统里面,model.conf的定义一般是不会在项目运行的时候改变的,所以它只能被加载,而不会被存储到存储系统如mysql;policy.csv的内容是容易变化的,所以policy.csv不仅可以被加载,也可以把数据存放到存储系统。
把policy.csv设计成一张mysql数据表需要包含下面的字段
id:表的主键
ptype:对应policy.csv里面的p,g等
v0~vn:这根据policy.csv里面具体的定义来决定有多少列,但是casbin的实现这里最多支持6列
如下
