工作原理

在 Casbin 中, 访问控制模型被抽象为基于 PERM (Policy, Effect, Request, Matcher) 的一个文件。 因此,切换或升级项目的授权机制与修改配置一样简单。 您可以通过组合可用的模型来定制您自己的访问控制模型。 例如,您可以在一个model中结合RBAC角色和ABAC属性,并共享一组policy规则。

PERM模式由四个基础(政策、效果、请求、匹配)组成,描述了资源与用户之间的关系。

请求

请求是一个元组对象,定义了应该提供访问控制匹配功能的参数名称和顺序。 至少由三部分组成:主题(访问实体)、对象(访问资源)、动作(访问方式)。 一个请求形如:r = {sub,obj,act}

策略

定义访问策略模式,是在策略规则文件中定义的。 例如:p={sub,obj,act}或者p={sub,obj,act,eft}。如果没有定义eft,那么策略文件中的结果字段就不会被读取,和匹配的策略结果将默认被允许。

匹配器

匹配请求和策略的规则。定义根据请求找到策略的方式。 例如:m = r.sub == p.sub && r.act == p.act && r.obj == p.obj,这个匹配规则表示如果请求的参数匹配策略中的资源和方法,那么就返回策略结果p.eft。

效果

可以被理解为一种模型,在这种模型中,对匹配的结果再次做出逻辑组合判断。 因为一个请求根据匹配器最终找到的策略可能不只一个。

例如:e = some(where(p.eft==allow))表示如果匹配的策略结果由一些是允许的,那么最终结果为真。 还有一个示例:e = some(where(p.eft==allow)) && !some(where(p.eft==deny))表示有匹配的allow的策略并且不存在有匹配deny的策略那么结果就为真。deny的优先级要高于allow

ACL示例

casbin支持的最简单的访问控制模型为ACL,那么就以一个完整的ACL模型为例。

首先是model文件中的配置,对上面的四部分进行了定义。

# 请求定义
[requet_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

这里定义了请求是由三部分组成的,策略也是由三部分组成的。请求和策略的匹配方式是两者的主题、对象、动作都一样。最终的效果是存在allow的策略结果结果就为真。

casbin中匹配器额定义可以使用\来支持多行模式。对于golang,还支持in操作,例如m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3'),但是数组的长度必须大于1,否则会panic。 `

然后在策略文件中编写具体的策略,ACL的示例策略为:

p, alice, data1, read
p, bob, data2, write

表示,alice可以读取data1,bob可以写data2。

匹配器中的函数

如何将请求与策略进行匹配是一个重点,为了便于灵活指定匹配规则,可以使用自定义的函数,也可以使用内置函数来辅助。下面介绍一下支持的内置函数。

除了keyGetkeyGet2,所有的内置函数的格式都要为

func function_name(arg1, arg2 string) bool

作用都是一样的,即arg1是否匹配arg2。而keyGetkeyGet2是返回匹配通配符的字符串,如果没有则返回空字符串。

内置函数

函数参数1参数2
keyMatch一个URL路径,例如/alice_data/resource1一个URL路径或*模式下,例如/alice_data/*
keyGet一个URL路径,例如/alice_data/resource1一个URL路径或*模式下,例如/alice_data/*
keyMatch2一个URL路径,例如/alice_data/resource1一个URL路径或:模式下,例如/alice_data/:resource
keyGet2一个URL路径,例如/alice_data/resource1一个URL路径或:模式下,例如/alice_data/:resource
keyMatch3一个URL路径,例如/alice_data/resource1一个URL路径或{}模式下,例如/alice_data/{resource}
keyMatch4一个URL路径,例如/alice_data/resource1一个URL路径或{}模式下,例如/alice_data//{id}/book/{id}
regexMatch任意字符串正则表达式模式
ipMatch一个IP地址,例如192.168.2.123一个 IP 地址或一个 CIDR ,例如192.168.2.0/24
globMatch类似路径的 /alice_data/resource1一个全局模式,例如 /alice_data/*

自定义函数

首先准备好自定义的函数,它接收一些参数并返回bool类型。

func KeyMatch(key1 string, key2 string) bool { 
	i := strings.Index(key2, "*") 
	if i == -1 { 
		return key1 == key2 
	} 
	if len(key1) > i { 
		return key1[:i] == key2[:i] 
	} 
	return key1 == key2[:i] 
}

然后用interface{}封装一下:

func KeyMatchFunc(args ...interface{}) (interface{}, error) { 
	name1 := args[0].(string) 
	name2 := args[1].(string) 
	return (bool)(KeyMatch(name1, name2)), nil 
}

在casbin的Enforcer中注册这个函数,

e.AddFunction("my_func", KeyMatchFunc)

最后就可以在model.conf中使用这个函数了

[matchers] 
m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act

实现ABAC