在 Go 中实现 ABAC
基于角色的访问控制回答的是“编辑能做什么?”很多实际规则光有角色是不够的:作者可以编辑自己的草稿,编辑可以编辑本部门的文章,任何人都可以阅读已发布的文章。这些规则依赖用户和资源的属性,这正是基于属性的访问控制(ABAC)的用途。
本教程用 Go 标准库的 net/http 包搭建一个小型文章 API,并把所有这些规则放在一个 Casbin 策略文件中。同样的模型和策略可以原样用于本教程的 Node.js 和 Python 版本。如果你 还在 RBAC 和 ABAC 之间犹豫,先读 选择访问控制模型。
1. 安装
http.ServeMux 中的方法和通配符模式需要 Go 1.22 或更高版本。
go mod init example.com/abac
go get github.com/casbin/casbin/v3
2. 编写模型
保存为 model.conf:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub_rule, obj_type, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.obj.Type == p.obj_type && r.act == p.act && eval(p.sub_rule)
- 这里的
r.sub和r.obj不是字符串,而是 Go 结构体。匹配器读取它们的字段,例如r.obj.Type。 - 每条策略规则都在
sub_rule中带一个条件。eval(p.sub_rule)针对请求对这个条件求值,所以规则放在策略中,而不是模型中。
3. 编写策略
保存为 policy.csv:
p, r.obj.Status == 'published', article, read
p, r.sub.Name == r.obj.Owner, article, read
p, r.sub.Name == r.obj.Owner && r.obj.Status == 'draft', article, update
p, r.sub.Role == 'editor' && r.sub.Department == r.obj.Department, article, update
p, r.sub.Role == 'editor' && r.sub.Department == r.obj.Department, article, publish
每一行可以读作“当条件为真时,允许对文章执行这个操作”:
- 任何人都可以阅读已发布的文章。
- 作者可以阅读自己的文章,包括草稿。
- 作者可以在文章还是草稿时编辑自己的文章。
- 编辑可以编辑本部门的任何文章。
- 编辑可以发布本部门的文章。
提示
条件中的字符串字面量用单引号,例如 'published'。字段中间出现双引号会破坏 CSV 解析。如果条件中需要逗号,用双引号把整个字段括起来。