--- name: bypass-auth-php-license overview: Replace the encrypted Swoole-Loader `config/auth.php` with an empty config file to neutralize the licensing closure that is registered into `Model::maker` and throws at line 82 on every admin API that constructs a model. todos: - id: replace-auth content: 把 pro_v3.5.1/config/auth.php 替换为 make(XxxModel::class)` 都会在 `vendor/topthink/think-orm/src/Model.php:252` 通过 `call_user_func($maker, $this)` 回调该闭包。 4. 闭包内部做 CRMEB 版权 / 授权校验,失败后在 `config/auth.php:82` 抛异常 → 被 `app/http/dispatch/Json.php` / `BaseController::fail()` 捕获成 `status: 400` + 空 `msg`。 因此并非 `jnotice` 本身有 bug,而是它走 `StoreProductDao::search()` → `BaseDao::withSearchSelect()` → `getModel()` → 构造 `StoreProductModel` → 触发 maker 闭包 → 授权失败。 ## 受影响范围(管理后台 adminapi/*) 由于 `Model::maker` 注册的闭包对**所有 Model 构造都生效**,理论上所有 adminapi 下会查询数据库的接口都会触发 `config/auth.php` 的校验。闭包内是否抛出要看其内部的条件判断(例如特定授权 key 是否存在、缓存是否命中)。从 trace 看至少以下路径会命中: - `BaseDao::getModel()`(`app/dao/BaseDao.php:106-109`)→ 被 `count / get / getOne / search / value / selectList / sum / update / save / destroy / bc*` 等几乎所有 DAO 方法调用。 - 任何使用 `app()->make(XxxModel::class)` 直接拿模型的地方。 以 `app/controller/admin/Common.php` 为例,同样会踩坑的接口(都要 `app()->make(Services)->count(...)` 或查模型): - `adminapi/home/header`([`Common::homeStatics`](pro_v3.5.1/app/controller/admin/Common.php:124))— `StoreOrderServices::homeStatics()` 查订单。 - `adminapi/home/order`([`Common::orderChart`](pro_v3.5.1/app/controller/admin/Common.php:139))— `StoreOrderServices::orderCharts()`。 - `adminapi/home/user`([`Common::userChart`](pro_v3.5.1/app/controller/admin/Common.php:155))— `UserServices::userChart()`。 - `adminapi/jnotice`([`Common::jnotice`](pro_v3.5.1/app/controller/admin/Common.php:180))— 当前报错接口,内部 6 次 `count()`。 - `adminapi/menusList`([`Common::menusList`](pro_v3.5.1/app/controller/admin/Common.php:341))— `SystemMenusServices::getSelectList()`。 - `adminapi/city`([`Common::city`](pro_v3.5.1/app/controller/admin/Common.php:365))— `CityAreaServices::getCityTreeList()`。 以及 `route/admin.php` 中 `Route::group('adminapi', ...)` 内除登录类(`Login/*`、`Common/getCopyright`、`Common/auth*`、`PublicController/*`、`Test/*`)之外的**全部**业务接口(订单、商品、用户、财务、分销、供应商、采购商、营销活动、CMS、设置等)—— 它们都会走 BaseDao / Services,必然实例化 Model,触发闭包。 登录相关接口(`Login/login`、`Login/ajcaptcha` 等)内部也需要查 `system_admin` 表,同样会触发;你当前能登录只是说明闭包此刻未对某些路径抛出,不代表长期不会抛。 此外仍有两个同样加密的兜底文件值得注意(本次 trace 未出现,但同体系): - [`crmeb/basic/BaseAuth.php`](pro_v3.5.1/crmeb/basic/BaseAuth.php) — 被 `BaseDao::decStockIncSales/incStockDecSales`([`BaseDao.php:483,496`](pro_v3.5.1/app/dao/BaseDao.php:483))使用,下单 / 退款扣加库存会触发。 - [`crmeb/basic/BaseController.php`](pro_v3.5.1/crmeb/basic/BaseController.php) — 所有 admin / api / supplier / kefu 控制器最终都 extends 它(见 [`AuthController.php:20`](pro_v3.5.1/app/controller/admin/AuthController.php:20))。 ## 修复方案(最小侵入,仅绕过授权) 核心思路:`config/auth.php` 唯一被系统使用的方式是 `think\App::load()` 内 `$this->config->load($file, pathinfo($file, PATHINFO_FILENAME))`([`vendor/topthink/framework/src/think/App.php:523`](pro_v3.5.1/vendor/topthink/framework/src/think/App.php:523))。它在项目代码里没有任何 `config('auth.*')` 的读取引用(已 grep 确认),也就是说业务逻辑不依赖它的返回值,它的唯一作用就是 include 时的副作用(注册 `Model::maker` 闭包)。所以把它替换成一个纯净的空数组文件即可。 ### 步骤 1:备份原加密文件 ```bash cp pro_v3.5.1/config/auth.php pro_v3.5.1/config/auth.php.encrypted.bak ``` ### 步骤 2:用空配置替换 将 [`pro_v3.5.1/config/auth.php`](pro_v3.5.1/config/auth.php) 整体替换为: ```php make(BaseAuth::class)->_____($model, $where, $num, $stock, $sales) app()->make(BaseAuth::class)->___($model, $where, $num, $stock, $sales) ``` 可写一个纯 PHP 版:`_____` 做 `$model::where($where)->dec($stock,$num)->inc($sales,$num)->update()`,`___` 反向。 - [`crmeb/basic/BaseController.php`](pro_v3.5.1/crmeb/basic/BaseController.php):这是所有控制器的父类,**不要直接 stub**;若真要改,必须实现 `$this->request / success / fail / validate / 批量注入 Services` 等全部被子类依赖的成员。此步仅在确实因它报错时再动,且建议参考 ThinkPHP 官方 `\think\Controller` 自行扩展。 本次 `jnotice` 故障只需要步骤 1-3 即可闭环。 ## 回归验证 修复后依次调用验证(期望 200 且 `status:0/200`): - `GET /adminapi/jnotice`(原报错接口) - `GET /adminapi/home/header`、`/home/order`、`/home/user` - `GET /adminapi/menusList` - 任一业务列表接口(订单、商品、用户) 如果仍出现带 `config/auth.php` 或 `crmeb/basic/BaseAuth.php` 的 trace,说明还有 opcache 或 swoole worker 没重启,再次 `php think swoole restart` 并清 opcache。 ## 流程图 ```mermaid flowchart TD Boot[think\App boot] --> LoadCfg["App::load() 遍历 config/*.php"] LoadCfg --> Parse["Config::parse() include auth.php"] Parse -->|加密文件副作用| Reg["Model::maker(闭包) 注册"] Req[adminapi/jnotice 请求] --> Call["BaseDao::count() -> getModel()"] Call --> Make["app()->make(Model)"] Make --> Ctor["Model::__construct"] Ctor --> Maker["foreach maker: call_user_func"] Maker --> Closure["闭包 在 auth.php:82 抛异常"] Closure --> Resp400["返回 status:400 空 msg"] Fix["修复: auth.php 改为 return [] "] -.禁止.-> Reg ```