前言
在应用开发中,为了保证资源的安全,经常设计一个资源授权系统来实现资源授权和权限。在动手开发前,我们需要了解常见有五种权限模型: ACL(权限控制列表)、RBAC(基于角色的访问控制)、ABAC(基于属性的访问控制)、DAC(自主访问控制)和MAC(强制访问控制)。其次,为了避免重复造轮子,我们需要了解一些优秀的开源库,如 Casbin 是一个功能强大且高效的开源访问控制库,支持各种访问控制模型以全面执行授权,支持访问控制模型,
本文主要介绍常见五种权限模型以及如何使用Casbin Golang来实现ACL、RBAC和ABAC。
常见的权限模型
- ACL(Access Control List 访问控制列表) ACL 是最基本和最简单的权限模型之一。它使用一个访问控制列表,列出了每个资源和允许访问该资源的用户或用户组。每个资源都有一个相关联的访问控制列表,控制了对该资源的访问权限。
- RBAC(Role-Based Access Control 基于角色的访问控制) RBAC 允许基于职位进行访问。RBAC 在很大程度上消除了提供对象访问权限时的自由裁量权。例如,人力资源专家不应该拥有创建网络帐户的权限;这应该是为网络管理员保留的角色。
- ABAC(Attribute-Based Access Control 基于属性的访问控制) 一种访问控制范例,通过使用评估属性(用户属性、资源属性和环境条件)的策略将访问权限授予用户
- MAC(Mandatory Access Control 强制访问控制) 在 MAC 中,用户没有太多自由来确定谁有权访问其文件。例如,用户的安全许可和数据的分类(机密、秘密或绝密)被用作安全标签来定义信任级别。
- DAC(Discretionary Access Control 自主访问控制) 在 DAC 中,数据所有者决定谁可以访问特定资源。例如,系统管理员可以基于某些权限创建要访问的文件的层次结构。
更多可以参考 访问控制模型
Casbin实现
Casbin 使用配置文件来定义访问控制模型。分别是:model.conf和policy.csv 。其中
- model.conf存储访问模型
- policy.csv存储具体的用户权限配置
Casbin的使用非常简单。我们只需要创建一个主要结构:enforcer。当构造这个结构时,model.conf和policy.csv就会被加载。
ACL
接着,我们以使用Casbin库实现ACL权限模型。
创建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
创建policy.csv
p, alice, data1, read
p, bob, data2, read
运行一个简单的ACL例子 example.go:用户(user)对数据(data)的读写(read)操作
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
panic(err)
}
sub := "alice" // 想要访问资源的用户。
obj := "data1" // 将被访问的资源。
act := "read" // 用户对资源执行的操作。
allowed, err := e.Enforce(sub, obj, act)
if err != nil {
panic(err)
}
if allowed {
fmt.Println("Access granted")
} else {
fmt.Println("Access denied")
}
}
运行输出
Access granted
RBAC
实现 RBAC 权限模型和ACL相似,多了角色定义, 其一,在模型配置定义角色、用户和权限,其二,在策略文件中指定用户-角色和角色-权限的关联。
model.conf
[policy_definition]
p = sub, obj, act
# 角色定义
[role_definition]
g = _, _
# 策略效果
[policy_effect]
e = some(where (p.eft == allow))
# 匹配器定义
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
policy.csv
p, alice, data1, read
p, bob, data2, read
#关联
g,alice,data2_admin
测试一下,同样运行example.go
运行输出
```js
Access granted
ABAC
实现 ABAC 权限模型,其一,在模型配置中定义资源、用户属性和环境属性,其二,在策略文件中指定策略规则。 model.conf
[request_definition]
r = sub, obj, act, resource
[policy_definition]
p = sub, obj, act, resource
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act && r.resource == p.resource
policy.csv
p, alice, data1, read, attribute1:value1
p, bob, data2, read, attribute1:value2
我们将上例example.go修改为ABAC的测试
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func main() {
enforcer, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
panic(err)
}
// 检查访问权限,包括属性
allowed, err := enforcer.Enforce("alice", "data1", "read", "attribute1:value1")
if err != nil {
fmt.Println("Failed to enforce policy:", err)
return
}
if allowed {
fmt.Println("value1 Access granted")
} else {
fmt.Println("value1 Access denied")
}
// 检查访问权限,包括属性
allowed, err = enforcer.Enforce("alice", "data1", "read", "attribute1:value2")
if err != nil {
fmt.Println("Failed to enforce policy:", err)
return
}
if allowed {
fmt.Println("value2 Access granted")
} else {
fmt.Println("value2 Access denied")
}
}
运行输出
value1 Access granted
value2 Access denied
总结
ACL权限模型较简单,不够灵活,功能单薄。RABC是比较常见,比如PostgreSQL作为其主要权限模型。ABAC提供了更动态的访问控制形式,基于属性的访问控制,比如阿里云的RAM都是ABAC 类型的权限访问服务。随着应用规模的增长,角色数量越来越多,选择适合的权限模型尤为重要。 Casbin可以简单的支持各种访问控制模型,还提供多种的adapter(file、sql、orm等类型) 实现,支持较多语言比如扩展到Go、Java、Node.js、Javascript(React)、Python、PHP、.NET、Delphi、Rust等,是个值得学习的统一访问控制框架。