casbin 权限模型和实例介绍

2,407 阅读3分钟

权限模型

casbin 使用的是 PERM(Policy, Effect, Request, Matchers) 来进行权限控制的。这四种实体之间相互作用的结果就可以用来进行授权的操作。

  1. Request: 请求的相关参数
  2. Policy: 控制请求访问的策略
  3. Matchers: 对 requestpolicies进行匹配
  4. 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

这个实例就是较为复杂一点的,不仅仅requestpolicy的定义中多了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,表示只有在角色名和用户名相同的时候,两者有关系(我觉得这个个数为 1 的是可以忽略的)
  2. 个数为2,表示的是策略中g后面的参数个数为2,分别表示用户和角色
  3. 个数为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
}