Go 中最强大的权限控制库(Casbin)

Go 中最强大的权限控制库(Casbin)

权限控制,它决定了 "谁能访问什么资源,能做什么操作"。

Casbin 是一个强大的、高效的开源访问控制框架,支持 ACL、RBAC、ABAC 等多种经典访问控制模型,通过配置文件即可灵活定义权限规则,同时支持策略的动态管理和持久化存储。

概念 作用 说明
Model(模型) 定义权限控制的逻辑 用 CONF 格式的文件或字符串编写,定义 "请求是什么、策略是什么、如何匹配、结果是什么"
Policy(策略) 定义具体的权限规则 可以存储在文件、数据库中,定义 "谁(用户 / 角色)能对什么资源做什么操作"
Adapter(适配器) 负责策略的存储和加载 支持文件、MySQL、PostgreSQL、Redis、MongoDB 等多种存储方式
Enforcer(执行器) Casbin 的核心组件 加载 Model 和 Policy,提供权限判断、策略管理等核心 API

ACL(访问控制列表)

ACL 是最简单的访问控制模型,直接定义 "用户 → 资源 → 操作" 的权限关系,适合小型项目或简单的权限场景。

编写 Model 文件(model.conf

Model 文件定义了权限控制的逻辑,Casbin 通过它来理解如何判断权限。

ini 复制代码
[request_definition]
# 定义请求的格式:r = [主体(sub), 客体(obj), 动作(act)]
# sub:用户/角色;obj:资源;act:操作(如 read、write)
r = sub, obj, act

[policy_definition]
# 定义策略的格式:p = [主体(sub), 客体(obj), 动作(act)]
p = sub, obj, act

[policy_effect]
# 定义策略效果:e = some(where (p.eft == allow))
# 意思是:只要有一条策略匹配且效果为 allow,就允许访问
e = some(where (p.eft == allow))

[matchers]
# 定义匹配规则:m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
# 意思是:请求的 sub、obj、act 必须和策略完全一致才匹配
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

编写 Policy 文件(policy.csv

Policy 文件定义了具体的权限规则,用 CSV 格式存储。

csv 复制代码
# p, 主体, 客体, 动作
p, zhangsan, /api/user, read
p, zhangsan, /api/user, write
p, lisi, /api/article, read

上面的策略表示:

  • zhangsan 可以对 /api/user 资源进行 readwrite 操作
  • lisi 可以对 /api/article 资源进行 read 操作

初始化 Enforcer:加载 Model 文件和 Policy 文件

go 复制代码
// 参数 1:Model 文件路径
// 参数 2:Policy 文件路径
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
        fmt.Printf("初始化 Enforcer 失败:%v\n", err)
        return
}
  • casbin.NewEnforcer(modelPath, policyPath) :初始化 Enforcer,加载 Model 和 Policy。

权限判断:使用 Enforce 方法

go 复制代码
// 参数顺序:sub, obj, act(和 Model 中 r 的定义一致)
// 场景 1:zhangsan 读取 /api/user
ok, err := e.Enforce("zhangsan", "/api/user", "read")
if err != nil {
        fmt.Printf("权限判断失败:%v\n", err)
        return
}
if ok {
        fmt.Println("zhangsan 允许读取 /api/user")
} else {
        fmt.Println("zhangsan 不允许读取 /api/user")
}

// 场景 2:lisi 写入 /api/article(策略中没有这条,应该拒绝)
ok, _ = e.Enforce("lisi", "/api/article", "write")
if ok {
        fmt.Println("lisi 允许写入 /api/article")
} else {
        fmt.Println("lisi 不允许写入 /api/article")
}
  • e.Enforce(sub, obj, act) :核心权限判断方法,参数顺序必须和 Model 中 r 的定义一致,返回 bool 表示是否允许访问。

RBAC(基于角色的访问控制)

RBAC 是企业开发中最常用的权限模型,它通过 "角色" 作为中间层,将用户与权限解耦(用户 → 角色 → 权限),大大简化了权限管理(比如给用户分配角色即可获得该角色的所有权限,无需逐个分配)。

编写 RBAC Model 文件(rbac_model.conf

RBAC 模型在 ACL 的基础上增加了角色定义(g角色继承

ini 复制代码
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
# 定义角色关系:g = [用户, 角色]
# 表示"用户属于某个角色"
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
# 匹配规则:g(r.sub, p.sub) 表示"请求的用户属于策略中的角色"
# 或者请求的用户直接等于策略中的主体(支持用户直接分配权限)
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

编写 RBAC Policy 文件(rbac_policy.csv

  • 角色权限

    • admin 可以对 /api/user/api/article 进行 readwrite
    • editor 可以对 /api/article 进行 readwrite
    • viewer 只能对 /api/article 进行 read
  • 用户角色

    • zhangsanadmin
    • lisieditor
    • wangwuviewer
csv 复制代码
# 1. 角色权限策略:p, 角色, 资源, 动作
p, admin, /api/user, read
p, admin, /api/user, write
p, admin, /api/article, read
p, admin, /api/article, write
p, editor, /api/article, read
p, editor, /api/article, write
p, viewer, /api/article, read

# 2. 用户角色策略:g, 用户, 角色
g, zhangsan, admin
g, lisi, editor
g, wangwu, viewer

动态管理用户角色

go 复制代码
// 给 wangwu 添加 editor 角色(现在 wangwu 是 viewer + editor)
added, err := e.AddRoleForUser("wangwu", "editor")
if added {
        // 保存策略到文件(生产环境用数据库适配器自动保存)
        e.SavePolicy()
}
// 现在 wangwu 应该允许写入 /api/article 了
ok, _ = e.Enforce("wangwu", "/api/article", "write")

// 删除 wangwu 的 viewer 角色
removed, err := e.DeleteRoleForUser("wangwu", "viewer")
if removed {
        e.SavePolicy()
}

动态管理权限

go 复制代码
// 给 editor 角色添加 /api/user 的 read 权限
added, err = e.AddPolicy("editor", "/api/user", "read")
if added {
        e.SavePolicy()
}
// 现在 lisi(editor)应该允许读取 /api/user 了
ok, _ = e.Enforce("lisi", "/api/user", "read")
API 作用
e.AddRoleForUser(user, role) 给用户添加角色
e.DeleteRoleForUser(user, role) 删除用户的角色
e.GetRolesForUser(user) 获取用户的所有角色
e.GetUsersForRole(role) 获取拥有该角色的所有用户
e.AddPolicy(sub, obj, act) 添加权限策略
e.DeletePolicy(sub, obj, act) 删除权限策略
e.SavePolicy() 保存策略到存储(文件 / 数据库)

RBAC with Domains(多租户 / 多部门)

如果你的系统是多租户(如 SaaS 平台)或多部门的,需要隔离不同租户 / 部门的权限,Casbin 支持 RBAC with Domains 模型,轻松实现权限隔离。

request_definitionmatchers 中增加 dom(域 / 租户)字段:

ini 复制代码
[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

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

权限判断和角色管理时需要增加 dom 参数:

go 复制代码
// 权限判断:sub, dom, obj, act
e.Enforce("zhangsan", "tenant1", "/api/user", "read")
// 给用户添加租户下的角色
e.AddRoleForUserInDomain("zhangsan", "admin", "tenant1")

数据库适配器

在开发环境中,我们可以用文件存储 Policy,但在生产环境中,通常需要用数据库存储 Policy,方便动态管理和持久化。Casbin 提供了丰富的数据库适配器,这里以最常用的 GORM Adapter(配合 MySQL)为例。

go 复制代码
// 1. 连接 MySQL 数据库
dsn := "root:your_password@tcp(127.0.0.1:3306)/casbin_demo?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

// 2. 初始化 GORM Adapter
// 参数 1:GORM DB 实例
// 参数 2:是否自动迁移(创建 casbin_rule 表)
a, err := gormadapter.NewAdapterByDB(db)

// 3. 初始化 Enforcer:加载 Model 文件和数据库 Adapter
e, err := casbin.NewEnforcer("./rbac_model.conf", a)

// 4. 初始化策略(仅第一次运行时执行,后续可注释)
// 添加角色权限
e.AddPolicy("admin", "/api/user", "read")
e.AddPolicy("admin", "/api/user", "write")
// 添加用户角色
e.AddRoleForUser("zhangsan", "admin")
// 保存策略到数据库
e.SavePolicy()

// 5. 权限判断
ok, _ := e.Enforce("zhangsan", "/api/user", "write")

// 6. 动态修改策略(自动同步到数据库)
e.AddRoleForUser("wangwu", "editor")
ok, _ = e.Enforce("wangwu", "/api/article", "write")
  • 自动同步 :使用数据库 Adapter 后,调用 AddPolicyAddRoleForUser 等 API 时,策略会自动同步到数据库,无需手动调用 SavePolicy()(部分 Adapter 需要,GORM Adapter 自动同步)。
  • 持久化:策略存储在数据库中,服务重启后不会丢失。
  • 动态管理:可以通过数据库直接管理策略,或通过后台管理界面调用 Casbin API 管理。

最佳实践

Model 设计

  • Model 文件独立存储 :将 Model 文件放在项目的 config 目录下,不要硬编码在代码里。
  • 从简单到复杂:优先使用 RBAC,只有在需要属性级权限控制时才用 ABAC。
  • 合理使用通配符 :Casbin 支持 * 通配符(如 p, admin, *, * 表示 admin 可以访问所有资源的所有操作),但要谨慎使用,避免权限过大。

策略管理

  • 生产环境用数据库 Adapter:不要用文件存储 Policy,推荐用 GORM Adapter 或 Redis Adapter。
  • 策略缓存:Casbin 内置了策略缓存,高并发场景下可大幅提升性能,默认开启。
  • 定期备份策略:定期备份数据库中的策略表,防止误操作导致策略丢失。

性能优化

  • 使用 EnforceContext :高并发场景下使用 EnforceContext 替代 Enforce,支持上下文传递和超时控制。
  • 批量权限判断 :使用 BatchEnforce 进行批量权限判断,性能更高。
  • 合理设计索引 :如果使用数据库 Adapter,确保 casbin_rule 表有合理的索引(GORM Adapter 会自动创建)。

安全注意事项

  • 不要在策略中存储敏感信息:策略仅存储权限规则,不要存储密码、密钥等敏感信息。
  • 最小权限原则:给用户和角色分配最小必要的权限,避免权限过大。
  • 权限验证前置:在 Gin/Echo 等框架的中间件中统一进行权限验证,避免每个接口都写权限判断代码。
相关推荐
NAGNIP2 小时前
一文搞懂CNN经典架构-ResNet!
算法·面试
腾讯云云开发2 小时前
用 OpenClaw + CloudBase 自动化开发网站:30分钟从安装到上线
后端·ai编程
独断万古他化3 小时前
【Java 实战项目】多用户网页版聊天室:消息传输模块 —— 基于 WebSocket 实现实时通信
java·spring boot·后端·websocket·ajax·mybatis
舒一笑3 小时前
🚀 我用一行命令,把 OSS 私有文件变成“可直接下载的公网链接”(很多人不会)
后端
小兔崽子去哪了3 小时前
Docker 安装 PostgreSQL
数据库·后端·postgresql
野犬寒鸦3 小时前
Redis热点key问题解析与实战解决方案(附大厂实际方案讲解)
服务器·数据库·redis·后端·缓存·bootstrap
snakeshe10103 小时前
深入理解 Java 注解:从原理到实战
后端
Lucaju3 小时前
吃透 Spring AI Alibaba 多智能体|四大协同模式+完整代码
后端
Nyarlathotep01134 小时前
Redis的对象(5):有序集合对象
redis·后端