在 Casbin 里,权限判断的核心不只在 model 定义本身,policy 规则如何落库、如何读回,同样决定了系统是否真正可用。本文把 adapter 的职责、内置 File adapter 的接入方式,以及自定义 Adapter 的实现边界拆开说明,帮助你判断什么时候直接用现成方案,什么时候需要自己接管持久化逻辑。
Adapter 在 Casbin 里负责什么
在 Casbin 中,适配器也就是 adapter,承担的是 policy 规则写入持久层的具体实现。Casbin 本身负责权限模型和决策逻辑,而 policy 存到哪里、怎么加载、怎么保存,则交给 adapter 来完成。

对使用者来说,最常见的两个入口方法是:
loadPolicy():从持久层加载policy规则savePolicy():把当前Policy规则保存到持久层
这意味着,Casbin 的 model 和 policy 并不是绑死在某一种存储方式上。你可以把规则放在文件里,也可以放进数据库,甚至接到自己的业务存储系统中。
原始设计上,Casbin 为了保持主库足够轻量,没有把各类 adapter 的实现都放进核心仓库,因此不同存储方案通常以独立扩展的形式提供。
内置 File adapter 怎么用
如果你只是想先把策略跑起来,文件适配器通常是最直接的选择。它会把 Policy 规则保存在 .csv 文件中,适合本地开发、功能验证,或者规则量不大且更新方式简单的场景。
最简用法是直接在创建 Enforcer 时传入 model 文件和 policy 文件路径:
$e = new Enforcer("path/to/model.conf", "path/to/policy.csv");
这种写法适合快速初始化,Casbin 会直接使用对应的文件适配方式来读取策略。
如果你希望先显式初始化 Adapter,也可以拆成两步:
use CasbinPersistAdaptersFileAdapter;
// 初始化一个适配器
$adapter = new FileAdapter("path/to/policy.csv");
// 用model文件和已有的适配器创建一个决策器
$e = new Enforcer("path/to/model.conf", $adapter);
拆开写的好处是更清晰,也方便你在项目启动阶段统一管理依赖。尤其当后续要从文件适配器切换到数据库适配器时,这种写法更容易保持初始化代码结构一致。
除了文件,还能把 Policy 存到哪里
Casbin 并不局限于文件存储,也支持把 Policy 放进数据库。对于实际项目来说,这通常才是更常见的落地方式,因为数据库更适合集中管理规则、支持多实例读取,以及配合后台管理系统动态维护权限数据。
官方已经为主流框架提供了相应扩展,方便直接在框架体系中接入 Casbin。
PHP 版本目前提供了 Laravel、Yii2、CakePHP、ThinkPHP 等主流框架的扩展,可以查阅官方仓库:
如果你的项目已经运行在这些框架中,优先考虑现成扩展通常更稳妥。原因很简单:这类扩展一般已经处理了框架内的数据库连接、服务注册和常见集成方式,能减少你自己补基础设施的工作量。
什么时候需要自定义 Adapter
当现成的文件适配器或框架扩展无法满足需求时,就需要自己实现 Adapter。典型场景包括:

- Policy 数据存放在公司内部的统一配置中心
- 权限规则需要走特殊的数据表结构
- 系统要对规则变更增加审计、同步或额外校验逻辑
自定义 Adapter 的门槛并不高,核心要求是实现 CasbinPersistAdapter 接口,也就是补齐 Casbin 所需的持久化操作。
class MyAdapter implements Adapter{
// 加载Policy
public function loadPolicy($model){
}
// 保存Policy
public function savePolicy($model){
}
// 新增Policy
public function addPolicy($sec, $ptype, $rule){
}
// 删除Policy
public function removePolicy($sec, $ptype, $rule){
}
// 删除符合筛选条件的policy规则
public function removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues){
}
}
从接口设计就能看出,自定义 Adapter 至少要覆盖几类操作:整体加载、整体保存、单条新增、单条删除,以及按条件批量删除。也就是说,它并不只是“把数据写进去”这么简单,而是要完整支撑 Casbin 在运行期对 policy 的常见读写行为。
这几个方法分别对应什么职责
loadPolicy($model) 用来把持久层中的规则读入当前模型;savePolicy($model) 负责把内存中的规则整体回写。它们更偏向全量同步。
addPolicy($sec, $ptype, $rule) 和 removePolicy($sec, $ptype, $rule) 则面向单条规则变更,适合在权限规则增删时做细粒度更新。
removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues) 的用途是按筛选条件删除一批匹配规则,这在批量清理某类角色、资源或动作对应的策略时会更高效。
自定义 Adapter 如何接入 Enforcer
实现完自定义适配器后,接入方式和内置适配器基本一致。关键点只有一个:在初始化决策器时,把你的 Adapter 实例传进去。
$adapter = new MyAdapter();
$e = new Enforcer("path/to/model.conf", $adapter);
这样,后续 Casbin 在执行 loadPolicy()、savePolicy() 或其他策略写入操作时,就会走你定义的持久化逻辑。
如果只是做本地验证,直接使用文件方式通常足够;如果项目已经有成熟框架和数据库体系,优先看官方扩展;而当你的规则存储流程明显有定制需求时,再实现自己的 Adapter,会是更合适的边界划分。









