权限模型
casbin 使用的是 PERM(Policy, Effect, Request, Matchers) 来进行权限控制的。这四种实体之间相互作用的结果就可以用来进行授权的操作。
- Request: 请求的相关参数
- Policy: 控制请求访问的策略
- Matchers: 对
request
和policies
进行匹配 - Effect: 用来组合策略匹配的结果来判断
request
的是否具有访问权限的结果
下图就包含四个实体之间是如何作用产生权限访问的
通过图中是可以知道的,request
需要和每个策略进行 match
产生 effect
,最后通过所有的effect
按照policy_effect
产生匹配的结果。
模型定义
下面的内容就是一个简单的权限控制中四个实体的定义文件中的内容, 文件名为 auth_model.conf
[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
定义中的 effect 在源码中是写死的四个(当然用户也可以自行定义)。此例中的表示的是request
匹配到策略中的任何一个就满足访问的权限。
定义中的 matchers 则表示匹配的策略,此例中表示的请求的每个字段和策略的每个字段都一一对应。
有了定义,还需要实体的策略,才可以判断request
的访问权限,实体策略可以如下,文件名为 policy.csv
p, alice, data1, read
p, bob, data2, write
实例介绍
实例1
此例子较为简单,就是按照上述介绍的例子进行数据操作的。
package main
import (
"fmt"
"github.com/casbin/casbin"
)
func main() {
e:= casbin.NewEnforcer("/path/to/auth_model.conf", "/path/to/policy.csv")
ok := e.Enforce("bob", "data2", "write")
fmt.Println("enforce result is ", ok) // enforce result is true
}
实例2
这个实例不仅包含用户的权限定义,还涉及到角色的定义,而且用户和角色还都有 domain 的限制。
auth_model_with_domain.conf 如下
[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 && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
policy_with_domain.csv 如下
p, admin, zhihu, /*, *
p, anonymous, zhihu, /login, *
p, member, zhihu, /logout, *
p, member, zhihu, /member/*, *
g, test, admin, zhihu
这个实例就是较为复杂一点的,不仅仅request
和policy
的定义中多了dom
,另外还涉及到用户和角色的定义role_definition
。最初看到这种定义的时候,我是比较懵逼的。_, _, _
这到底是干啥的,做啥的???有的时候_
个数是2,有的时候还是为3。直到看了源码,才晓得这其中的关系。
// GenerateGFunction is the factory method of the g(_, _) function.
func GenerateGFunction(rm rbac.RoleManager) func(args ...interface{}) (interface{}, error) {
return func(args ...interface{}) (interface{}, error) {
name1 := args[0].(string)
name2 := args[1].(string)
if rm == nil {
return name1 == name2, nil
} else if len(args) == 2 {
res, _ := rm.HasLink(name1, name2)
return res, nil
} else {
domain := args[2].(string)
res, _ := rm.HasLink(name1, name2, domain)
return res, nil
}
}
}
角色关系的定义要看g
表达式后面的_
的个数的:
- 个数为1,表示只有在角色名和用户名相同的时候,两者有关系(我觉得这个个数为 1 的是可以忽略的)
- 个数为2,表示的是策略中
g
后面的参数个数为2,分别表示用户和角色 - 个数为2,表示的是策略中
g
后面的参数个数为3,分别表示用户,角色和 domain
domian
的意思类似于用户和角色具有关系的条件,比如说策略中包含多个应用的数据,policy.csv 中最后一条策略表示的就是只有在 zhihu
这个 domain(可以理解为应用)
下 test 才具有 admin
的角色,而在其他 domain
下 test 就不会具有 admin
的角色了
实例代码如下
package main
import (
"fmt"
"github.com/casbin/casbin"
)
func main() {
e := casbin.NewEnforcer("/paht/to/auth_model_with_domain.conf", "/path/to/policy_with_domain.csv")
ok := e.Enforce("test", "zhihu", "/login", "admin")
fmt.Println("enforce result is ", ok) // enforce result is true
}