在使用casbin之前,要理解他的model
PERM元模型
1 2 3 4 5 6 7 8 9 10 11
| [request_definition] r = sub, obj, act
[policy_definition] p = sub, obj, act, (eft)
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
|
- P [policy_definition] 策略
- E [policy_effect] 效果
- R [request_definition] 请求
- M [matchers] 匹配
sub(subject)=请求实体 obj(object)=访问资源
act(action)=访问方法 (write,read) eft(effect)=策略结果
具体流程
- 系统设定策略 p, sub ,obj, act, (eft)
- 用户 在[request_definition]中 输入 sub , obj , act
- 在[matchers]中 将用户输入的和系统设定的策略相互匹配,匹配到了返回allow,否则deny,并把结果存入p.eft
- 在[policy_effect]中,如果匹配到,返回true,表示你获得权限,否则没有
实战
1 2 3 4 5 6 7 8 9 10 11 12
| // 模型 [request_definition] r = sub, obj, act
[policy_definition] p = sub, obj, act
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
|
- 示例
1 2 3 4 5 6 7 8
| // 用户输入 alice, data1, read // 系统设定策略(这个就是开发者可以修改) p, alice, data1, read p, bob, data2, write // 对照发现第一条可以匹配得到 // 返回 true
|
- 示例
1 2 3 4 5 6 7 8
| // 用户输入 alice, data1, read // 系统设定策略(这个就是开发者可以修改) p, alice, data1, read , deny p, bob, data2, write // 对照发现第一条可以匹配得到,但是匹配到的eft是deny // 返回 false
|
同时,匹配规则是定死的,只有那么几个可以选
Policy Effect |
含义 |
|
some(where (p.eft == allow)) |
有一条匹配到就行 |
|
!some(where (p.eft == deny)) |
只要存在一个策略的效果(eft)为拒绝(deny),那么访问就会被拒绝。 |
|
some(where (p.eft == allow)) && !some(where (p.eft == deny)) |
要存在至少一个策略的效果为允许(allow),并且不存在任何一个策略的效果为拒绝(deny) |
|
priority(p.eft) || deny |
如果优先级存在(非零),或者出现了拒绝访问的情况 |
|
subjectPriority(p.eft) |
subjectPriority(p.eft) |
|
总结
具体来说就是比较
将用户输入数据与系统设定策略比较
得到**比较结果,allow/deny
再用比较结果与系统设定的比较结果相比较
返回true / deny 来判断是否有权限
单商户模型(进阶1)
在原来的模型上,引入角色(role)的概念,得到单商户模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [request_definition] r = sub, obj, act
[policy_definition] p = sub, obj, act
[role_definition] g = _, _
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
|
大多数地方都与上述的PERM元模型一致
[role_definition]
g = _, _
引入角色的概念,其实并不难理解,角色与用户是相等地位的,可以理解每个用户对应一个角色
在 g = _ ,_ 中 分别输入 g = 用户 ,角色 (具体设定是在策略中实现)
g(r.sub, p.sub)
代表了 Casbin 中的策略函数调用
说人话就是把用户和角色对应了起来
实战
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [request_definition] r = sub, obj, act
[policy_definition] p = sub, obj, act
[role_definition] g = _ , _
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
|
- 示例
1 2 3 4 5 6 7 8 9 10 11
| // 用户输入 alice,想要访问data1,用于读的权限 alice, data1, read // 系统策略 p, admin_alice, data1, read admin_alice 这个role角色读取data1的权限 p, alice, data1, read alice 本身用户拥有读取data1的权限
g, alice, admin_alice 将 alice用户 和 admin_alice 角色相绑定 // 匹配两者 allow // 结果 true
|
- 对示例1稍微修改一下
1 2 3 4 5 6 7 8 9 10 11
| // 用户输入 alice,想要访问data1,用于读的权限 alice, data1, read // 系统策略 p, admin , data1, read admin 这个role角色读取data1的权限
g, alice, admin_alice 将 alice用户 和 admin_alice 角色相绑定 // 匹配两者 deny // 结果 false // alice获得的是admin_alice 的权限,而不是admin所以false
|
- 对示例1稍微修改一下啊
1 2 3 4 5 6 7 8 9 10 11 12
| // 用户输入 alice,想要访问data1,用于读的权限 alice, data1, read // 系统策略 p, admin, data1, read admin_alice 这个role角色读取data1的权限 p, alice, data1, read alice 本身用户拥有读取data1的权限
g, alice, admin_alice 将 alice用户 和 admin_alice 角色相绑定 // 匹配两者 allow // 结果 true // 虽然alice 没有获得admin的权限,但是他本身这个名字就有权限了,所以返回true
|
总结
角色 与 用户 两者就是等价的,要用g(,)把两者绑定一下
然后就可以在策略中书写role的权限,可扩展性增加
多商户模型(进阶2)
在原来的模型上,引入 域(domain)的概念
可以把domain 理解为 某个角色/用户 在某个范围 可以做某些事情,但是在其他范围不能做
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [request_definition] r = sub, dom, obj, act
[policy_definition] p = sub, dom, obj, act
[role_definition] g = _, _, _
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
|
[request_definition]
r = sub, dom, obj, act
需要在 输入的时候 输入用户的domain
[role_definition]
g = _, _, _
这里有三个横线了,分别是 g = 用户,角色,域
用户和角色等价,两者在域之中
g(r.sub, p.sub, r.dom)
绑定一下关系 ,请求的实体和系统设定的实体需要在相同的domain中
实战
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [request_definition] r = sub, dom, obj, act
[policy_definition] p = sub, dom, obj, act
[role_definition] g = _, _, _
[policy_effect] e = some(where (p.eft == allow))
[matchers] m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
|
- 示例
1 2 3 4 5 6 7 8 9 10 11
| // 用户输入 alice, domain1, data1, read 在domain1中的alice想要有data1的read权限
// 系统输入 p, alice, domain1,data1, read domain1的alice用户可以read来data1 p, admin, domain1,data1, read domain1的admin角色可以read来data1
g, alice, admin, domain1 alice用户--admin角色--属于domain1 // 比较 allow // 返回 true
|
- 修改一下
1 2 3 4 5 6 7 8 9 10 11 12
| // 用户输入 alice, domain1, data1, read 在domain1中的alice想要有data1的read权限
// 系统输入
p, admin, domain1,data1, read domain1的admin角色可以read来data1
g, alice, admin, domain2 alice用户--admin角色--属于domain2 // 比较 allow // 返回 false // 因为这里系统输入中是admin-domain2,所以与系统设定的策略admin-domain1不正确
|
- 再修改一下
1 2 3 4 5 6 7 8 9 10 11 12
| // 用户输入 alice, domain1, data1, read 在domain1中的alice想要有data1的read权限
// 系统输入 p, alice, domain1,data1, read domain1的alice用户可以read来data1 p, admin, domain1,data1, read domain1的admin角色可以read来data1
g, alice, admin, domain2 alice用户--admin角色--属于domain1 // 比较 allow // 返回 true // 这里g, alice, admin, domain2虽然改成了domain2,但是这里是最纯粹的p, alice, domain1,data1, read 可以与输入的相互匹配
|
注意:
1 2 3 4 5 6
| p, role , data, read p, role , domain, data, read
// 这两个策略想要实现,必须要在策略中实现 g , 用户, _ , _ // 不然会输出false
|
总结
用户 可以理解为个人
角色 可以理解为某个职务
域 可以理解为某个部门
一般来说,都是某个某个职务在某个部门有哪些权限
如果要为某个人开个特定的权限,就可以直接写 p, alice , domain , data1, read 之类的