访问控制是指区分不同用户对不同资源的访问能力,在应用系统中通常叫做权限管理。
在做任何多用户系统的时候,用户权限管理都是整个系统中必不可少的部分,并且权限设计要做到既安全又清晰是一件不太容易的事情。
根据不同的场景,权限管理可以设计出各种不同的模型。
今天就给各位介绍一个访问控制框架:Casbin 以及 PERM 元模型。
Casbin · An authorization library
元模型 PERM
如果,在做系统设计时,针对每一个资源和每一个用户都编写访问规则将会是一个工作量很大的事情,并且对于动态变化的资源和用户,这样做是不可行的。因此我们需要定义一系列规则,这些规则的组合就是一个访问控制模型。
PERM 模型是由 4 个基础( Policy,Effect,Request,Matchers )描述各个资源和用户之间的相互关系。
Request 请求
定义了请求参数。一个基本的请求是一个元组对象,至少包含 subject (访问实体), object (访问的资源)和 action (访问方法)。
r={sub, obj,act}
它其实就是定义了传入访问控制匹配函数的参数名和顺序。
Policy 策略
定义访问策略的模型。其实就是定义 Policy 规则文档中各字段的名称和顺序。
p={sub, obj, act} 或 p={sub, obj, act, eft}
注意:如果不定义 eft(策略结果),那么将不会去读策略文件中的结果字段,并将匹配的策略结果都默认为 allow 。
Matchers 匹配规则
Request 和 Policy 的匹配规则。
例如: m = r.sub == p.sub && r.act == p.act && r.obj == p.obj
这条简单又常见的匹配规则的意思就是,请求的参数(实体、资源和方法)都相等即在策略中能找到,那么返回策略结果(p.eft)。策略结果会保存在 p.eft 中。
Effect
用于将给定请求与最终结果匹配的策略组合 /减少的策略的模型。可以理解为,对 Matchers 匹配后的结果再进行一次逻辑组合判断的模型。 例如:==e = some(where(p.eft == allow)) 这句的意思是指,如果匹配策略结果 p.eft 存在(some) allow 的结果,那么最终结果就为 真 再看个例子: e = some(where (p.eft == allow)) && !some(where (p.eft == deny)) 这个例子组合的逻辑含义是:如果有匹配出结果为 alllow 的策略并且没有匹配出结果为 deny 的策略则结果为真,换句话说,就是匹配的策略都为 allow 时才为真,如果有任何 deny,都为假 (更简单的说当 allow 和 deny 同时存在时,deny 优先)
以上是 PERM 的模型定义的说明,接下来,用 Casbin 实战一下:
Casbin 访问控制需要两个东西:访问控制模型文件和策略文件,模型文件就是上文描述的内容。
下图说明了如何使用基于 PERM 的模型授权请求。 创建一个完整的模型文件
创建一个 perm.conf 文件,内容如下:
#Request definition
[request_definition]
r = sub, obj, act
#Policy definition
[policy_definition]
p = sub, obj, act, eft # 这里我们定义了 eft,不使用默认值
#Policy effect
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny)) # 这里使用了 deny 优先
#Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act #最简单的匹配规则。请求的参数与策略参数一致时获得策略结果
注意代码中的注释
创建一个 policy.csv 文件, 其中的每个字段的定义就如 perm 中[policy_definition]中定义的顺序:
p, zeta, data1, read, allow
p, bob, data2, write, allow
p, zeta, data2, write, deny
p, zeta, data2, write, allow
p 代表策略组名称,就是 metchers 里对应的那个 p 。后面的 zeta,data, read, allow 对应的就是策略定义中的 sub,obj,act 和策略结果 eft 。
假如,request 参数在策略文件中能够匹配( zeta,data1 和 read ),那么结果为 allow ; 假如,request 参数在策略文件中能够匹配( zeta,data2,write ),那么结果为 deny,同时也匹配另一条策略结果为 allow,根据 policy_effect 的定义,依然识别为假。
接下来用 Go 代码检验一下 创建 main.go 代码如下:
package main
import (
“fmt”
“github.com/casbin/casbin”
)
func main() {
//通过策略文件和模型配置穿件一个 casbin 访问控制实例
e := casbin.NewEnforcer(“./perm.conf”, “./policy.csv”)
//定义各种 sub,obj 和 act 的数组
subs := []string{“bob”, “zeta”}
objs := []string{“data1”, “data2”}
acts := []string{“read”, “write”}
//遍历组合 sub,obj,act 并打印出对应策略匹配结果。
for _, sub := range subs {
for _, obj := range objs {
for _, act := range acts {
fmt.Println(sub, “/“, obj, “/“, act, “=“, e.Enforce(sub, obj, act))
}
}
}
}
这段 Go 代码很简单,组合每一种 sub 、obj 和 act,然后打印出访问控制的结果验证我们的策略文件和模型的设计。
运行结果为:
bob / data1 / read = false
bob / data1 / write = false
bob / data2 / read = false
bob / data2 / write = true
zeta / data1 / read = true
zeta / data1 / write = false
zeta / data2 / read = false
zeta / data2 / write = false
bob 的策略很简单,只有 data2 的 write 结果为 allow,因此其余都是 false,结果正确; zeta 对 data1 的 read 结果为 allow,对 data2 的 write 同时有 allow 和 denny (根绝 policy_effect 定义的 deny 优先),因此结果 zeta 也只对 data1 的 read 为 true,结果正确。
这样,我们就使用 Casbin 和 PERM 创建了一个基础的访问控制模型设计和策略。
在实际应用上,如果我们做的是一个 Web 应用,可以将路由作为 obj,请求方式 Method 作为 act,登录用户的角色作为 sub,在每一次请求时,把这 3 个参数传递给 e.Enforce, 就可以实现对 Web 页面和请求接口的权限控制管理,非常方便。
存储 Casbin 除了能够通过策略文件和模型配置文件设置访问控制外,还可以适配数据库模式,将策略和模型保存在数据库中,更适合大型复杂的软件系统的权限管理。 model 存储 policy 存储
函数
文中的模型配置没有使用额外的函数,但是在实际应用中,对与资源的匹配模式,action 的匹配模式可能会用到更高级的匹配方法。利用函数是最佳实践方式。 Policy 存储 · Casbin
API
Casbin 提供给了很多 API 用于管理 管理 API · Casbin
1
GM 2021-01-05 17:46:20 +08:00
不.......不明觉厉?!
|
2
raaaaaar 2021-01-05 20:23:04 +08:00 via Android 1
这种文章总有种说的不是人话的感觉
|
3
GopherDaily 2021-01-05 20:35:11 +08:00
@raaaaaar introduction for intrdocution
|
4
GopherDaily 2021-01-05 20:35:40 +08:00
纯当看书的笔记的话还好
|
5
YouLMAO 2021-01-05 20:37:48 +08:00 via Android
Apache ranger 真好用,QPS 杠杠的话
|
6
dobelee 2021-01-05 20:43:09 +08:00 via iPhone 1
在用了。坑还是很多的。
|
7
loading 2021-01-05 20:58:40 +08:00 via Android
没有脚手架的话,刚入门根本玩不起来。
|
8
dcoder 2021-01-06 03:50:10 +08:00 1
所有复杂的权限 access control 框架, 都会慢慢演化成折腾 DSL ...
那么问题来了, 为啥不直接用程序逻辑实现? |
9
gmywq0392 2021-01-06 09:50:11 +08:00
OPA 玩家路过
|