Authorization - Casbin Storage
Model Storage
- Casbin 中模型的三种加载方式
- 模型是”只读“的
- Casbin 的 Model 定义了访问控制逻辑(谁能对什么资源做什么操作),运行时被视为静态配置
- 没有 API 可以保存或更新模型 - 它是设计时确定的,不是动态变化的
关键区别
| 方式 | 适用场景 | 优点 |
|---|---|---|
| CONF 文件 | 大多数情况 | 清晰、可分享、易维护 |
| 代码构建 | 需要程序化组装模型 | 灵活、可条件拼接 |
| 字符串 | 配置中心/DB 存储 | 适合集中管理 |
- 三种方式加载的模型内容完全相同,区别只在于来源不同
- 模型一旦加载完成,后续的动态变化都体现在 Policy(策略) 上,而不是 Model 上
从 .conf 文件加载(推荐)
最常用的方式,把模型定义写在独立的配置文件中,便于分享和讨论
1 | [request_definition] # 请求定义:请求有哪些字段 |
使用时一行代码创建 Enforcer
1 | e := casbin.NewEnforcer("rbac_model.conf", "rbac_policy.csv") |
从代码中构建
适合需要动态组装模型的场景,通过
AddDef()逐条添加定义
1 | m := model.NewModel() |
从字符串加载
适合模型存储在配置中心或数据库的场景
1 | text := `[request_definition] |
Policy Storage
核心思想:Model 定义规则逻辑,而 Policy 存储具体规则数据,两者分离
CSV 文件存储(最简单)
策略以 CSV 格式存储,每行一条规则
1 | p, alice, data1, read # alice 可以读 data1 |
- p 开头:策略规则(policy),对应 Model 中的 policy_definition
- g 开头:角色继承(grouping),对应 Model 中的 role_definition
- 所以上面 alice 既能读 data1(直接授权),又能读写 data2(通过 data2_admin 角色继承)
CSV 转义规则 - 逗号用双引号包裹,内部双引号用 “” 转义
| 场景 | 正确写法 | 错误写法 |
|---|---|---|
| 字段含逗号 | p, alice, “data1,data2”, read | p, alice, data1,data2, read |
| 字段含逗号和引号 | p, alice, data, “r.act in (“”get””, “”post””)” | p, alice, data, “r.act in (“get”, “post”)” |
Adapter API(适配器接口)
Adapter 是 Casbin 与存储后端之间的桥梁:
| 方法 | 类型 | 说明 |
|---|---|---|
| LoadPolicy() | 基础(必须实现) | 从存储加载所有策略规则 |
| SavePolicy() | 基础 | 将所有策略规则保存到存储 |
| AddPolicy() | 可选 | 新增一条策略规则 |
| RemovePolicy() | 可选 | 删除一条策略规则 |
| RemoveFilteredPolicy() | 可选 | 按条件批量删除策略规则 |
- 基础方法 = 所有 Adapter 必须实现
- 可选方法 = 按需实现,未实现时 Casbin 会退回到全量 SavePolicy()
数据库存储格式
CSV 里的策略存到数据库时,会被”展平“成通用表结构
CSV
1 | p, data2_admin, data2, read |
数据库表
| id | ptype | v0 | v1 | v2 | v3 | v4 | v5 |
|---|---|---|---|---|---|---|---|
| 1 | p | data2_admin | data2 | read | |||
| 2 | p | data2_admin | data2 | write | |||
| 3 | g | alice | admin |
各列含义:
- ptype:规则类型(p、g、g2 等),对应 CSV 中第一个字段
v0~`v5`:按顺序存储后续字段,最多 6 列(部分 Adapter 支持更多)
本质上就是 把 CSV 的每一行拆成类型 + 按序号排列的字段,是一种通用的、与具体模型无关的存储格式
总结对比
换存储后端只需换 Adapter,Model 和业务代码完全不用动
1 | Model = 规则引擎(逻辑) |
1 | flowchart LR |
Loading Policy Subsets
核心概念
- 背景问题:在大规模或多租户场景下,把所有策略一次性加载到内存不现实 - 内存占用过大 + 加载速度慢
- 解决方案:只加载需要的那部分策略子集
两个核心 API
LoadFilteredPolicy(filter)
- 按 filter 条件从存储中加载策略,替换当前内存中的策略
- 加载后 SavePolicy() 被禁用 - 防止只有部分策略在内存的情况下把残缺数据写回存储,覆盖掉完整策略
LoadIncrementalFilteredPolicy(filter)
- 同样按 filter 条载入策略,但是追加到当前内存策略,而非替换
- 可以多次调用,每次加载一个租户/域的策略,最终合并成一个 enforcer
代码解析
1 | // 使用支持过滤的适配器(FilteredAdapter) |
Filter 结构的字段含义:
| 字段 | 对应 CSV 列 | 作用 |
|---|---|---|
| P: []string{“”, “domain1”} | policy (p) 规则 | 第1列(sub)不限,第2列必须是 “domain1” |
| G: []string{“”, “”, “domain1”} | grouping (g) 规则 | 第1、2列不限,第3列必须是 “domain1” |
空字符串 “” 表示该位置不过滤(通配)
典型使用场景对比
| 场景 | 用哪个 |
|---|---|
| 单个租户,切换域 | LoadFilteredPolicy — 替换掉旧的 |
| 多个租户合并到一个 enforcer | LoadIncrementalFilteredPolicy — 依次追加 |
| 全量加载 | 普通 LoadPolicy |
关键约束
LoadFilteredPolicy 之后 SavePolicy() 被禁用
原因:内存中只有部分策略,如果 SavePolicy 把内存数据写回存储,会把其他域/租户的策略清空,造成数据丢失
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.








