必须严格按casbin通用格式设计casbin_rule表(6字段、固定顺序)、enforcer单例化初始化、thinkorm预加载角色与权限策略,三者缺一不可,否则动态菜单和按钮权限失效。

直接用 Webman + Casbin + ThinkORM 落地 RBAC,不是“能跑就行”,而是要扛住后台管理系统的实际压力:菜单动态加载、按钮级控制、角色继承、数据权限预留扩展点。关键在 casbin_rule 表结构设计、Enforcer 初始化时机、以及权限校验与 ThinkORM 关联查询的耦合点——这三处写错,后面所有动态菜单和按钮指令都会失效。
casbin_rule 表字段必须严格按 Casbin 通用格式建
很多人照着 ER 图建表,把 casbin_rule 当成普通业务表,加了自增 ID、created_at 等字段,结果 Enforcer 加载失败或策略漏匹配。
- Casbin 要求该表只有 6 列(p_type + 4 个参数 + effect),顺序不能乱:
p_type、v0、v1、v2、v3、v4、effect - RBACK 模型下,
p_type固定为p(policy)或g(group),v0是用户/角色标识,v1是资源(如/api/user或user:list),v2是动作(GET/POST/edit) -
effect必须是allow或deny,不能留空或写1/0,否则enforcer.Enforce(...)返回false却不报错 - 别手动 INSERT 策略,用
enforcer.AddPolicy()或enforcer.AddGroupingPolicy(),它们会自动处理字段映射和去重
ThinkORM 关联查询必须预加载角色+权限策略
登录后查用户菜单、按钮权限时,如果只查 sys_user 再嵌套 N+1 查询角色、再查 casbin_rule,接口延迟直接上 300ms+。Webman 的协程优势就废了。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 用户模型
SysUser要定义roles()关联,角色模型SysRole定义permissions()关联到casbin_rule(注意:不是查业务权限表,是直连casbin_rule) - 登录成功后,用
SysUser::with(['roles.permissions'])->find($uid)一次查出全部策略,再手动组装成['user:list', 'user:edit']这类权限点数组 - 不要依赖 Casbin 的
GetFilteredPolicy()去实时筛用户权限——它每次都要全表扫描casbin_rule,QPS 上不去 - 若需支持角色继承(如 “运营主管” 继承 “运营专员” 权限),
casbin_rule中必须存g类型规则:g, role:manager, role:operator
Webman 中间件里 Enforcer 不能每次 new
在中间件 handle() 里写 $enforcer = new Enforcer(...),等于每个请求都重建适配器、重连数据库、重加载全部策略——内存暴涨,MySQL 连接数瞬间打满。
- 把
Enforcer实例挂到 Webman 的容器里,例如在config/bootstrap.php中:Container::set(Enforcer::class, function () { return new Enforcer('rbac_model.conf', new DatabaseAdapter(...)); }); - 中间件中用
$enforcer = Container::get(Enforcer::class)获取单例,启动时加载一次策略,后续复用 - 如果策略会动态变更(如后台改权限),调用
$enforcer->loadPolicy()刷新,但别在每次请求里无脑 reload - 注意
DatabaseAdapter的连接配置要设'persistent' => true,否则协程切换时连接丢失
按钮权限控制别只靠前端 v-if,后端必须二次校验
前端用权限点做 v-if="hasPermission('user:delete')" 是必要体验优化,但绝不能替代后端校验。否则绕过前端、直发请求,删库跑路。
- Webman 路由定义时,给需要按钮级控制的接口加中间件,例如:
->middleware(CheckPermissionMiddleware::class) - 中间件里取当前用户权限数组(从 Token 解析或 Session 读取),再调
$enforcer->enforce($role, $resource, $action),其中$resource建议统一用路由名(如user.delete),$action固定为 HTTP 方法小写(delete) - 避免用路径做
$resource(如/api/v1/user/123),因为带 ID 的路径无法被 Casbin 规则泛化匹配,得写一堆通配符规则,维护爆炸 - 数据权限(如“只能看本部门数据”)此时要介入:校验通过后,在查询前用 ThinkORM 的
where()自动追加部门 ID 条件,这个逻辑必须和权限校验在同一中间件链里完成
最易被忽略的是 casbin_rule 表的索引——v0+v1+v2 三个字段必须联合索引,否则 Enforce() 查询慢到不可用;还有就是 ThinkORM 的模型关联没设 foreignKey,导致预加载失效却无报错,查半天发现数据是空的。










