告别硬编码权限:Cerbos 权限管理引擎深度解析
在开发企业级应用时,权限控制(Authorization)往往是最令开发者头疼的部分。起初,你可能只需要简单的 if user.Role == "admin";但随着业务增长,你会发现权限逻辑变得极其复杂:“只有在周一到周五,且属于财务部门,且该文档状态为‘草稿’时,经理才能编辑”。
如果你将这些逻辑硬编码在 Golang 业务代码中,你的代码库将充斥着大量的 if/else,且每次修改权限规则都需要重新编译部署。Cerbos 正是为了解决这个问题而生的。
什么是 Cerbos?
Cerbos 是一个开源的、解耦的权限管理引擎。它将权限策略(Policy)从应用程序代码中完全分离。
简单来说,Cerbos 就像是一个“权限判定黑盒”:
1. 你的应用:向 Cerbos 发送一个请求(“用户 A 能对资源 B 执行操作 C 吗?”)。
2. Cerbos:根据预定义的策略文件(YAML 格式)进行计算。
3. 结果:Cerbos 返回 Allow(允许)或 Deny(拒绝)。
核心特性
- 策略即代码 (Policy as Code):权限规则写在 YAML 文件中,支持版本控制(Git)。
- 支持多种模型:原生支持 RBAC(基于角色的访问控制)和 ABAC(基于属性的访问控制)。
- 高性能:采用 Go 语言开发,提供极低的延迟。
- 无状态:Cerbos 不存储你的用户数据或资源数据,它只负责逻辑判定,这意味着它极易扩展。
Cerbos 的工作原理
Cerbos 采用的是一种请求-响应模式。它不关心你的数据库怎么设计,它只关心你传给它的“快照”。
一个典型的权限检查请求包含三个要素:
1. Principal (主体):谁在请求?(包含 ID、角色、部门等属性)。
2. Resource (资源):请求操作的对象是什么?(包含 ID、所有者、状态等属性)。
3. Action (动作):想要做什么?(例如 read, update, delete)。
实战演练:构建一个文档管理系统的权限控制
假设我们要实现这样一个需求: - 管理员 (Admin):可以执行任何操作。 - 编辑 (Editor):可以编辑所有文档,但不能删除。 - 作者 (Author):只能编辑和删除自己创建的文档。
1. 定义策略文件 (policies/document.yaml)
在 Cerbos 中,你不需要写 Go 代码,而是编写如下 YAML:
apiVersion: api.cerbos.io/v1
resourcePolicy:
# 资源名称
resource: "document"
# 定义允许的操作
rules:
# 规则 1: 管理员拥有所有权限
- actions: ["create", "read", "update", "delete"]
effect: EFFECT_ALLOW
roles: ["admin"]
# 规则 2: 编辑者可以读取和更新
- actions: ["read", "update"]
effect: EFFECT_ALLOW
roles: ["editor"]
# 规则 3: 作者只能操作自己的文档 (ABAC 核心)
- actions: ["read", "update", "delete"]
effect: EFFECT_ALLOW
roles: ["author"]
condition:
match:
# 匹配主体 ID 与 资源的所有者 ID
expr: request.principal.id == request.resource.attr.ownerId
2. 在 Golang 中集成 Cerbos
首先,安装 Cerbos 的 Go SDK:
go get github.com/cerbos/cerbos-go
接下来,在你的业务逻辑中调用:
package main
import (
"context"
"fmt"
"log"
"github.com/cerbos/cerbos-go"
)
func main() {
// 1. 初始化 Cerbos 客户端 (假设 Cerbos 服务运行在 localhost:3590)
client, err := cerbos.NewClient("localhost:3590", cerbos.WithInsecure())
if err != nil {
log.Fatal(err)
}
// 2. 模拟一个请求场景:作者尝试删除一个文档
// 主体:用户 ID 为 "user_123",角色为 "author"
principal := &cerbos.Principal{
Id: "user_123",
Roles: []string{"author"},
}
// 资源:文档 ID 为 "doc_abc",所有者为 "user_123"
resource := &cerbos.Resource{
Id: "doc_abc",
Attr: map[string]interface{}{
"ownerId": "user_123",
},
}
// 动作:删除
action := "delete"
// 3. 向 Cerbos 发起判定请求
resp, err := client.CheckPermission(context.Background(), &cerbos.CheckPermissionRequest{
Principal: principal,
Resource: resource,
Action: action,
})
if err != nil {
log.Fatal(err)
}
// 4. 根据结果执行业务逻辑
if resp.Effect == cerbos.EffectAllow {
fmt.Println("✅ 权限允许:可以删除该文档")
} else {
fmt.Println("❌ 权限拒绝:你没有权限删除此文档")
}
}
为什么选择 Cerbos 而不是传统的数据库权限表?
1. 动态性与灵活性
在传统方案中,如果你想增加一个“只有在文档处于‘审核中’状态时才能编辑”的规则,你需要修改数据库 Schema 或在代码中增加复杂的 WHERE 子句。
在 Cerbos 中,你只需要修改 YAML 文件的 condition 部分,然后通过 API 刷新策略,无需重启服务,无需修改代码。
2. 统一的权限语言
在一个大型微服务架构中,可能有 Java 写的用户服务、Go 写的订单服务、Node.js 写的文档服务。如果每个服务自己实现权限逻辑,会导致规则不一致。 Cerbos 提供了一个统一的权限平面,所有服务都调用同一个 Cerbos 集群,确保权限判定标准全局统一。
3. 极简的测试
由于策略是独立的 YAML 文件,你可以编写专门的测试用例来验证权限逻辑,而不需要启动整个复杂的业务系统。
总结:适用场景
你应该在以下情况下考虑使用 Cerbos:
- 你的权限逻辑已经复杂到让 if/else 无法维护。
- 你需要实现复杂的 ABAC(基于属性)权限控制。
- 你在构建微服务架构,需要统一的权限管理中心。
- 你希望由产品经理或安全审计员能够直接阅读(甚至修改)权限规则,而不需要阅读源代码。
Cerbos 将权限从“开发任务”变成了“配置任务”,让 Golang 开发者能够专注于核心业务逻辑,而将复杂的访问控制交给专业的引擎处理。



还没有评论,来说两句吧...