应将权限判断逻辑从控制器抽离为独立策略类,统一实现check接口并返回policyresult对象,通过容器自动解析策略名、依赖ability门面而非rbac细节,严格遵循策略只决策不越界原则。

权限判断逻辑散落在控制器里,改起来像拆炸弹
直接在 index() 或 update() 里写一堆 if ($user->role === 'admin' || in_array($resource, $user->perms)),短期能跑,后期加个“部门协同编辑”规则就得翻三页代码找漏点。这不是逻辑复杂,是职责错位——控制器不该知道“谁能在什么条件下删订单”。
把权限判定抽成独立类,用策略模式按场景分发:订单删除走 OrderDeletePolicy,报表导出走 ReportExportPolicy,每个类只专注一类规则的组合与短路逻辑。
- 所有策略类统一实现
check(User $user, array $context = []): bool接口 - 策略名必须带业务动词+资源名,比如
ApplyRefundPolicy,避免模糊的AuthPolicy - ThinkPHP 的服务容器可自动绑定,注册时用
$this->app->bind('OrderDeletePolicy', OrderDeletePolicy::class)
策略类里硬编码 RBAC 规则,一换权限模型就全崩
别在 OrderDeletePolicy::check() 里写死 return $user->hasRole('manager') || $user->hasPermission('order:delete:own')。RBAC 是实现细节,不是策略契约。真正该依赖的是抽象能力查询,比如 $this->ability->can('delete', 'order', $order)。
ThinkPHP 自带的 think-auth 或自研权限中间件,应提供统一的 Ability 门面,策略类只调它,不碰角色表、权限表、关系表。
- 策略类构造函数注入
Ability实例,而非User模型 -
$context参数传具体资源实例(如$order),让Ability内部决定要不要查数据权限 - 避免在策略里调
Db::table('auth_rule')->where(...)—— 这等于把 SQL 当策略
策略切换靠 if-else 分支,新增类型要改调度器
常见反模式:if ($action === 'delete') { new OrderDeletePolicy(); } elseif ($action === 'export') { new ReportExportPolicy(); }。每次加新动作就得打开调度文件,手动加分支,还容易漏 default 报错。
用命名约定 + 容器自动解析更稳:策略类名固定为 {Resource}{Action}Policy,运行时拼出类名,让容器 resolve。ThinkPHP 的 Loader::parseName() 可转下划线为驼峰,Str::studly() 也能用。
- 调度入口写成
$policyClass = "app\policy\" . Str::studly($resource . '_' . $action) . 'Policy' - 必须加
class_exists($policyClass)判断,不存在时抛PolicyNotFoundException,别静默 fallback - 不要用
eval()或call_user_func()动态调用 —— IDE 失去跳转,PHPStan 直接报错
策略返回 true/false,但前端需要“为什么没权限”
用户点删除按钮没反应,日志里只有 access denied,运营来问“张三为啥不能删这个订单”,你得翻四层代码才定位到是部门隔离规则拦截了。策略接口必须支持反馈原因。
把返回值从 bool 升级为对象:PolicyResult,含 allowed: bool 和 reason: string 属性。控制器拿到后,开发环境可直接输出 $result->reason 到响应头或日志。
-
PolicyResult::denied('需部门主管审批')比return false多 10 行代码,但省下 2 小时排查时间 - 禁止在
reason里暴露数据库字段名或 SQL 片段,用业务语言:“当前订单处于退款中,不可删除” - 前端调试时,可在响应 header 加
X-Permission-Reason,仅限 dev 环境开启
策略模式本身不难,难的是所有人遵守“策略只决策、不查库、不渲染、不记录日志”的边界。一旦某个策略开始读 session、写缓存、触发钩子,整套机制就退化成带包装的 if-else。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











