用 PHP-Casbin 做权限控制时,如何使用自定义函数

青禾
青禾
发布时间:2026-08-25 | 174人浏览过
原创

前言

很多团队接入 PHP-Casbin 后,基础权限规则很快能跑起来,但一遇到“超级管理员直接放行”这类需求,就容易把逻辑散落到业务代码里。其实更合适的做法,是把判断封装成自定义函数接进 Matcher;本文就用一个最小示例,把模型修改、函数注册和结果验证三步讲清楚。

很多项目在落地权限系统时,都会先用 ACL、RBAC 或 ABAC 的现成模型,但一旦出现“某类用户跳过常规校验”的需求,单靠基础规则就不够用了。PHP-Casbin 这类场景的处理方式并不复杂:把业务判断写成自定义函数,再放进 Matcher 表达式里参与决策。下面就用“超级管理员直接放行”这个常见需求,拆开看配置、注册和验证三个关键步骤。

安装 PHP-Casbin

如果项目还没有引入 Casbin 依赖,先执行安装命令:

composer require casbin/casbin

文章里的示例使用原生 PHP 演示。如果你在 Laravel、ThinkPHP、Yii 等框架中接入,一般可以直接使用对应扩展提供的封装,核心思路并不会变化,重点仍然是围绕 Enforcer 和 Matcher 来组织权限判断。

先准备 Enforcer 和基础模型

在 PHP-Casbin 里,权限决策由 Enforcer 负责执行,而判断逻辑则写在模型配置中。这里先用一个最基础的 basic_model 作为起点:

[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

这段配置的含义比较直接:请求里的 sub、obj、act 需要和策略中的对应字段全部匹配,才会被放行。也就是说,它适合标准的“谁对什么资源做什么动作”判断,但还没有覆盖“特殊身份绕过规则”的需求。

接着实例化一个决策器:

<?php

require_once './vender/autoload.php';

use CasbinEnforcer;

$enforcer = new Enforcer('path/to/basic_model.conf');

到了这一步,基础的权限校验环境已经具备。接下来要做的,不是重写整套权限逻辑,而是在现有 Matcher 上增加一个额外判断入口。

如何把自定义函数接入 Matcher

假设现在有一个明确需求:如果当前用户是超级管理员,就不再继续比对普通权限策略,直接允许访问。这个场景特别适合用自定义函数来处理,因为它本质上是一个独立的业务判断。

展示 PHP-Casbin 中请求、Matcher、自定义函数与普通策略判断关系的专栏式配图
自定义函数在权限决策里的位置把自定义函数插入 Matcher 后,权限决策会先判断特殊身份,再决定是否继续走常规策略匹配。

首先要修改模型里的 matchers 表达式:

[matchers]
m = checkIsAdmin(r.sub) || (r.sub == p.sub && r.obj == p.obj && r.act == p.act)

这里新增了一个 checkIsAdmin(r.sub)。它接收请求中的 sub 参数,并返回一个 bool 结果。整个表达式使用了逻辑或 ||,因此只要这个函数返回 true,后面的普通权限匹配就不会继续成为放行门槛。

换句话说,这一行配置把权限决策拆成了两层:

  • 第一层,先判断请求主体是否属于特殊身份;
  • 第二层,如果不是,再按照原有的 sub / obj / act 规则继续校验。

这种写法的价值在于,它对原有策略模型的侵入很小。你不需要把“超级管理员”这类特殊角色硬编码进每一条策略里,只需要在 Matcher 增加一个可复用的业务函数即可。

注册 checkIsAdmin 并实现超级管理员放行

模型里写了函数名之后,还需要在已经实例化好的 Enforcer 上真正注册这个函数。PHP-Casbin 提供了添加函数的方法,传入函数名和方法体即可:

$enforcer->addFunction('checkIsAdmin', function(string $sub): bool {
    // 假设如果传入的 sub 等于 root ,即认为是超级管理员
    return $sub === 'root';
});

这段代码里,checkIsAdmin 的判断逻辑非常简单:只要传入的 sub 等于 root,就视为超级管理员,函数返回 true。在真实项目里,你当然可以把这部分替换成更贴近业务的数据判断,比如查角色表、查租户配置,或者根据用户上下文判断是否具备全局权限。

但无论内部逻辑怎么变化,接入方式都保持一致:Matcher 只关心函数最终返回的是 true 还是 false。这也是自定义函数最实用的地方,它把复杂业务判断封装在模型之外,同时仍然能自然参与 Casbin 的权限决策流程。

验证结果是否符合预期

函数注册完成后,可以直接通过 enforce 来验证效果:

展示 root 与普通用户在 PHP-Casbin 中得到不同 enforce 结果的对比配图
普通用户与超级管理员的决策结果对比验证阶段最重要的不是代码长短,而是同一资源请求在普通用户和特殊用户之间是否得到稳定、可解释的不同。
$res = $enforcer->enforce('aclie', 'data', 'read');
var_dump($res); // false

$res = $enforcer->enforce('root', 'data', 'read');
var_dump($res); // true

从这两次调用可以很清楚地看出差异:

  • aclie 不是超级管理员,checkIsAdmin 返回 false,因此会继续走后面的常规权限匹配;示例里没有命中策略,所以结果是 false。
  • root 会让 checkIsAdmin 返回 true,于是直接放行,最终结果就是 true。

如果你的目标正是“某个身份跳过普通规则”,那验证时最关键的判断依据就是:同样的资源和动作,在普通用户与特殊用户之间,是否能稳定得到不同的决策结果。只要这一点成立,说明自定义函数已经真正进入了权限链路,而不是停留在单独的业务代码里。

这种做法适合放到哪些场景

这个例子虽然简单,但已经足够说明 PHP-Casbin 自定义函数的用法:把特殊业务逻辑写成函数,通过 addFunction 注册,再在 Matcher 中组合进最终决策表达式。

它特别适合下面这类需求:

  • 超级管理员、系统账号、内部服务账号的特殊放行;
  • 需要在权限判断前增加额外条件;
  • 不想大范围改动已有策略结构,只想局部增强判断逻辑。

对实际项目来说,这种方式的优势不在于“功能多高级”,而在于改动点集中、接入成本低,也不会为了一个特殊规则去大面积侵入现有权限代码。只要 Matcher 设计得清楚,自定义函数就能成为 Casbin 中非常灵活的一层扩展能力。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表