Go 与 Casbin 技术实践:从权限模型到代码落地
Go 与 Casbin 技术实践:从权限模型到代码落地
在后端系统开发中,权限控制几乎是绕不开的话题。一个稍微复杂一点的系统,往往都会遇到这样几个问题:谁可以访问某个接口?谁可以操作某类资源?管理员和普通用户的权限边界如何划分?如果继续通过大量 if-else 或硬编码的方式维护权限逻辑,代码会很快变得混乱且难以扩展。
这时,Casbin 就是一个非常值得引入的权限控制框架。
Casbin 是一个强大的、支持多种访问控制模型的开源权限管理库,支持 ACL、RBAC、ABAC 等主流模型,并且可以很好地与 Go 项目集成。本文会先介绍 Casbin 的核心模型,再通过一个 Go 示例展示如何与 Casbin 进行交互。
一、Casbin 是什么
Casbin 是一个统一的访问控制框架,它将“权限判断逻辑”从业务代码中抽离出来,让开发者通过“模型 + 策略”的方式来定义访问控制规则。
简单来说,Casbin 主要解决的是下面这个问题:
某个用户
sub,是否可以对某个资源obj执行某个操作act?
例如:
alice是否可以读取data1bob是否可以写入data2admin是否可以删除某个订单
Casbin 并不要求你把权限判断逻辑写死在代码里,而是通过配置文件来表达规则,这样系统的扩展性和维护性都会更高。
二、Casbin 的核心组成
Casbin 的权限控制通常由两部分组成:
- 模型(Model):定义权限判断的结构和逻辑
- 策略(Policy):定义具体的权限数据
可以把它理解为:
- 模型 决定“权限判断规则长什么样”
- 策略 决定“谁拥有什么权限”
例如,一个典型的权限判断语句如下:
alice, data1, read
它可以表示:用户 alice 对资源 data1 拥有 read 权限。
而 Casbin 会根据模型中的匹配逻辑,判断这条策略是否满足访问请求。
三、Casbin 模型详解
Casbin 的模型通常定义在一个 .conf 文件中。对于初学者来说,最常见的是 RBAC 或 ACL 风格模型。
下面是一个比较经典的模型示例:
[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
下面分别解释这四个部分。
1. request_definition
[request_definition]
r = sub, obj, act
这部分定义了“请求”的结构。
也就是说,每次做权限校验时,Casbin 都会接收一个请求,这个请求由三个字段组成:
sub:主体(subject),通常表示用户、角色或系统主体obj:资源对象(object),通常表示接口、文件、订单、菜单等资源act:操作(action),通常表示 read、write、delete 等动作
例如:
ok, err := e.Enforce("alice", "data1", "read")
这里的:
alice对应subdata1对应objread对应act
2. policy_definition
[policy_definition]
p = sub, obj, act
这部分定义了“策略”的结构。
策略可以理解为一条条权限记录。例如:
p, alice, data1, read
p, bob, data2, write
表示:
alice可以读取data1bob可以写入data2
p 就代表一条 policy 规则。它的字段结构需要和模型中的 p = sub, obj, act 对应起来。
3. policy_effect
[policy_effect]
e = some(where (p.eft == allow))
这部分定义了策略生效方式,也就是“多条策略匹配时,最终如何决策”。
这句的含义是:
只要存在一条策略结果是
allow,就允许访问。
这是 Casbin 中最常见的一种策略效果。
在实际项目中,你还可能看到更复杂的效果表达式,例如同时处理 allow 和 deny,但对于入门来说,先理解“命中一条允许规则即可放行”就足够了。
4. matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
这部分是 Casbin 模型里最核心的部分,它定义了“请求”和“策略”如何进行匹配。
这句的意思很直白:
- 请求中的
sub必须等于策略中的sub - 请求中的
obj必须等于策略中的obj - 请求中的
act必须等于策略中的act
只有三者都匹配,Casbin 才会认为该请求被这条策略命中。
例如:
请求:
(alice, data1, read)
策略:
(alice, data1, read)
那么匹配成功,返回允许。
但如果请求变成:
(alice, data1, write)
由于 act 不匹配,因此不会通过。
四、Casbin 中的 RBAC 思想
上面的模型更接近 ACL。实际开发中,更常见的是 RBAC(基于角色的访问控制)。
RBAC 的核心思想是:
不直接给用户分配权限,而是先给角色分配权限,再把用户绑定到角色上。
这样做的好处是权限管理更加灵活。
例如:
admin角色拥有全部后台管理权限editor角色拥有文章编辑权限guest角色只有查看权限
用户只需要绑定角色即可。
一个简单的 RBAC 模型通常会多出角色继承定义:
[request_definition]
r = sub, obj, act
[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
这里的关键点在于:
g(r.sub, p.sub)
它表示:请求中的用户 r.sub 是否具有策略中 p.sub 这个角色。
例如:
p, admin, /user/list, read
p, admin, /user/create, write
g, alice, admin
表示:
admin角色可以读取/user/listadmin角色可以写入/user/createalice拥有admin角色
因此,alice 也就具备了对应权限。
五、Go 中如何集成 Casbin
下面通过一个简单示例,看看 Go 如何与 Casbin 交互。
1. 安装依赖
先在项目中安装 Casbin:
go get github.com/casbin/casbin/v2
2. 编写模型文件 model.conf
[request_definition]
r = sub, obj, act
[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
这个模型使用的是 RBAC。
3. 编写策略文件 policy.csv
p, admin, /user/list, read
p, admin, /user/create, write
p, user, /profile, read
g, alice, admin
g, bob, user
这表示:
admin角色可以读取用户列表、创建用户user角色可以读取个人信息alice属于adminbob属于user
4. Go 示例代码
下面是一段完整的 Go 示例代码:
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
func main() {
e, err := casbin.NewEnforcer("model.conf", "policy.csv")
if err != nil {
log.Fatalf("failed to create enforcer: %v", err)
}
checkPermission(e, "alice", "/user/list", "read")
checkPermission(e, "alice", "/user/create", "write")
checkPermission(e, "bob", "/profile", "read")
checkPermission(e, "bob", "/user/create", "write")
}
func checkPermission(e *casbin.Enforcer, sub, obj, act string) {
ok, err := e.Enforce(sub, obj, act)
if err != nil {
log.Printf("enforce error: sub=%s obj=%s act=%s err=%v", sub, obj, act, err)
return
}
fmt.Printf("user=%s, obj=%s, act=%s, allowed=%v\n", sub, obj, act, ok)
}
六、代码解析
这段代码的核心流程并不复杂。
1. 创建 Enforcer
e, err := casbin.NewEnforcer("model.conf", "policy.csv")
Enforcer 可以理解为 Casbin 的执行器。它负责:
- 加载模型配置
- 加载策略数据
- 根据模型匹配规则执行权限判断
在项目运行过程中,几乎所有权限判断都要通过 Enforcer 来完成。
2. 执行权限校验
ok, err := e.Enforce(sub, obj, act)
这是 Casbin 最核心的调用方式。
Enforce 会根据你传入的请求参数:
- 当前访问者是谁
- 正在访问什么资源
- 想执行什么操作
然后去匹配模型和策略,最终返回一个布尔值:
true:允许访问false:拒绝访问
例如:
ok, _ := e.Enforce("alice", "/user/list", "read")
由于 alice 绑定了 admin 角色,而 admin 拥有 /user/list 的 read 权限,因此返回 true。
而:
ok, _ := e.Enforce("bob", "/user/create", "write")
由于 bob 只绑定了 user 角色,不具备该权限,因此返回 false。
七、运行结果示例
执行程序后,你可能看到类似输出:
user=alice, obj=/user/list, act=read, allowed=true
user=alice, obj=/user/create, act=write, allowed=true
user=bob, obj=/profile, act=read, allowed=true
user=bob, obj=/user/create, act=write, allowed=false
这正符合我们在策略中定义的权限规则。
八、Casbin 在实际项目中的常见用法
在真实项目里,Casbin 通常不会只停留在这个简单示例层面,而是会进一步结合以下场景:
1. 与 Web 框架中间件结合
在 Gin、Echo、Fiber 等 Go Web 框架中,Casbin 常常被封装为中间件:
- 请求进入时先解析当前用户身份
- 再提取请求路径和请求方法
- 最后调用
Enforce判断是否允许访问
例如,可以把:
- 用户 ID / 角色 作为
sub - URL 路径作为
obj - HTTP 方法(GET、POST、PUT、DELETE)作为
act
这样就能对接口做统一权限控制。
2. 使用数据库存储策略
入门示例常用 policy.csv 保存策略,但在生产环境中,权限规则通常存放在数据库中,以便动态维护。
例如:
- 后台管理系统修改角色权限
- 实时增删策略
- 多实例服务共享统一权限数据
Casbin 提供了 Adapter 机制,可以把策略存储到 MySQL、PostgreSQL、SQLite 等数据库中。
3. 支持更复杂的权限模型
除了 RBAC,Casbin 还支持:
- ACL:面向具体用户授权
- ABAC:基于属性进行权限控制
- RBAC with Domains:支持租户、多组织、多空间场景
因此它不仅适合简单后台系统,也适合中大型 SaaS 系统。
九、为什么在 Go 项目中推荐 Casbin
对于 Go 项目而言,Casbin 有几个非常明显的优势:
1. 解耦权限逻辑与业务逻辑
如果把权限判断写在业务代码中,随着接口增多,代码会越来越难维护。而 Casbin 把权限规则抽离出来,让业务代码只关注业务本身。
2. 模型灵活
Casbin 并不是只支持一种固定的权限模式,而是允许开发者通过模型文件定义自己的规则。
3. 易于扩展
无论是从文件策略升级到数据库策略,还是从简单 ACL 升级到 RBAC、多租户模型,Casbin 都能平滑演进。
4. 与 Go 生态结合自然
Casbin 的 Go 版本使用非常直接,API 清晰,适合快速接入现有服务。
十、总结
Casbin 的核心价值在于:它通过“模型 + 策略”的方式,把权限控制从业务代码中独立出来,让系统权限管理更加清晰、灵活和可维护。
对于初学者来说,理解 Casbin 最重要的是先掌握下面几点:
request_definition定义请求结构policy_definition定义策略结构policy_effect定义策略生效方式matchers定义请求与策略的匹配逻辑
在 Go 中使用 Casbin 也非常简单,通常只需要:
- 定义模型文件
- 定义策略文件
- 创建
Enforcer - 调用
Enforce做权限判断
如果你的项目正面临权限逻辑越来越复杂、角色越来越多、接口访问控制越来越难维护的问题,那么 Casbin 会是一个非常值得引入的解决方案。
附:一个更贴近接口权限控制的思路
在实际 Web 项目中,你还可以把接口权限设计为:
sub:当前用户角色,如admin、editor、guestobj:接口路径,如/api/ordersact:HTTP 方法,如GET、POST、DELETE
例如策略可以写成:
p, admin, /api/orders, GET
p, admin, /api/orders, POST
p, editor, /api/orders, GET
p, guest, /api/orders, GET
这样 Casbin 就可以很好地服务于 RESTful API 权限控制场景。
如果后续继续深入,你还可以进一步研究:
- Casbin 与 Gin 中间件整合
- Casbin 的数据库 Adapter
- Casbin 的 RBAC 多租户模型
- 基于路径匹配的权限控制(如
keyMatch)
这些能力可以让 Casbin 在企业级 Go 项目中发挥更大的价值。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)