QQ扫一扫联系
「CLI 管理授权」为命令行工具 modstart-cli 提供后台管理能力的接入底座:在后台生成 CLI 凭证并精确勾选可调用的接口,命令行工具凭凭证登录后即可调用 /{adminPath}/cli/* 下的后台管理接口,各模块通过 AdminCli 目录(Controller + routes.php + api.json)提供自己的 CLI 接口与接口描述。
admin-cli-key 请求头,管理员身份取凭证绑定的账号。api.json 描述,客户端 modstart-cli api list 可直接发现接口,call <key> '<json>' 按参数定义在本地校验后调用,输出统一为 code / msg / data。「CLI 管理授权」为命令行工具(modstart-cli)提供后台管理能力接入:
{adminPath}/cli/* 下的后台管理接口module/<Module>/AdminCli 中提供 CLI 控制器与 api.json 接口 schema,供 CLI / AI 发现admin-cli-keymodstart-cli 支持凭证登录、多站点、接口列表与 JSON 调用,输出统一为 code / msg / dataCLI 管理授权
凭证
后台生成
一次性明文显示
有效期 / 撤销
仅创始人可创建
接口授权
模块 → 接口树状勾选
按接口 key 精确授权
founderOnly 接口仅创始人
安全
只认 admin-cli-key
不依赖 Session / 角色
列表字段脱敏
写接口字段白名单
客户端
凭证登录
多站点
api list
call 调用(JSON)
--admin-url 填完整后台管理地址):modstart-cli login --admin-url=https://your-domain.com/admin --token=mscli_xxxxxxxx --name=MacBook
modstart-cli whoami
modstart-cli api list
modstart-cli call news.index '{"page":1,"pageSize":20}'
modstart-cli call news.add '{"title":"标题","content":"内容"}'
modstart-cli call news.category.index
call 的参数统一为 JSON 对象(也可用 --data '<json>'),会按接口定义在本地校验参数(必填、int/bool/json 类型),参数不合法会直接提示,不会发送到后台。
所有 CLI 接口统一位于后台前缀下:/{adminPath}/cli/*。
| 接口 | 方法 | 说明 |
|---|---|---|
cli/me | GET/POST | 当前凭证绑定的管理员与授权接口 |
cli/api_list | GET/POST | 当前可用接口 schema(按凭证授权接口过滤) |
cli/<module>/... | 按定义 | 各模块 CLI 管理接口 |
所有 CLI 接口都必须携带admin-cli-key请求头,每次请求都会复验凭证状态(撤销/过期立即失效),后台面板 Cookie 不能单独访问 CLI;CLI 完全无状态,不读写 Session/Cookie,管理员身份始终取凭证绑定的adminUserId;凭证创建时勾选的接口白名单会参与授权(未勾选的接口直接拒绝,也不出现在api_list中)。
业务模块在 module/<Module>/AdminCli/ 下提供三部分即可,不需要修改后台原控制器:
module/News/AdminCli/
├── Controller/
│ ├── NewsCliController.php
│ └── CategoryCliController.php
├── routes.php
└── api.json
控制器(@Api 注解 + 真实逻辑,标准 CRUD 可复用 CliCrud):
<?php
namespace Module\News\AdminCli\Controller;
use Illuminate\Routing\Controller;
use ModStart\Admin\Auth\Admin;
use ModStart\Admin\Auth\AdminPermission;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Input\Response;
use Module\AdminCli\AdminCli\CliCrud;
use Module\News\Model\News;
class NewsCliController extends Controller
{
use CliCrud;
/**
* @Api 新闻资讯 列表
* @ApiDesc 分页查询,只返回白名单字段
* @ApiMethod post
* @ApiBodyParam page int 页码
* @ApiBodyParam pageSize int 每页数量
*/
public function index()
{
return $this->paginateModel(News::class, 'title', [], ['id', 'title', 'created_at']);
}
/**
* @Api 新闻资讯 新增
* @ApiMethod post
* @ApiBodyParam title string required 标题
* @ApiBodyParam content string 内容
*/
public function add()
{
AdminPermission::demoCheck();
// 写接口必须传 $allow 白名单,被拒参数会显式报错
$data = $this->modelInput(News::class, ['id', 'created_at', 'updated_at'], ['title', 'content']);
$id = ModelUtil::insert(News::class, $this->withRequiredDefaults(News::class, $data));
Admin::addInfoLog(Admin::id(), 'CLI 新增新闻', ['ID' => $id]);
return Response::generateSuccessData(['id' => $id]);
}
}
路由(相对 {adminPath}/cli,由 AdminCli 自动挂载):
<?php
/* @var \Illuminate\Routing\Router $router */
$router->match(['post'], 'news/index', 'NewsCliController@index');
$router->match(['post'], 'news/add', 'NewsCliController@add');
接口 schema(api.json,供 CLI / AI 发现):
{
"module": "News",
"title": "新闻资讯",
"apis": [
{
"key": "news.index",
"title": "新闻资讯 列表",
"method": "post",
"url": "news/index",
"scope": "news.read",
"permission": "\\Module\\News\\Admin\\Controller\\NewsController@index",
"params": [
{ "name": "page", "type": "int", "required": false, "desc": "页码" }
]
}
]
}
字段说明:
| 字段 | 说明 |
|---|---|
key | 全局唯一标识,CLI 使用 call <key> 调用 |
title | 接口中文说明 |
method | 请求方法(post / get) |
url | 相对 {adminPath}/cli 的地址 |
scope | 接口分类元数据(不参与授权) |
permission | 保留字段,不再参与授权 |
params | 参数定义,供 CLI 帮助、参数校验与 AI 生成调用;必须与控制器实际可写字段一致 |
founderOnly | true 表示仅创始人可调用(后台没有可授权规则的接口使用,如 MemberApiKey、PayUnifiedClient),非创始人的授权树与 api_list 中都不展示 |
返回 HTML 页面的接口(show详情、login/logout、GET-only 的param/dashboard/export等)不要声明为 CLI 接口。
routes.php 路由、控制器方法、api.json 缺任何一项都会被 fail-closed 拒绝。*Manage 规则;无规则接口标 founderOnly。paginateModel() 优先显式传字段白名单;不传时默认剔除 password/passwordSalt/secret/apiKey/token/openid/unionid/idCard/bankCard/realname 等;裸 key/token 列需在模块侧白名单排除。money|order|pay|charge|cash|credit|…)必须传 $allow;被拒参数显式报错,禁止静默丢弃;password/passwordSalt/remember_token 永远不可通过通用输入写入。AdminPermission::demoCheck(),并 Admin::addInfoLog() 记录操作。founderOnly 等安全用例按负向断言补充。ModelUtil::*、paginateModel()、modelInput()、withRequiredDefaults() 一律传 \Module\X\Model\Xxx::class,禁止字符串表名;表没有 Model 时先在 Model/ 补最小模型再写业务。admin_cli_token.apis;运行时不检查后台角色与权限规则api_list 中api.json 标 founderOnly,由中间件强制创始人校验,非创始人的授权树中也看不到scope 仅作为接口分类元数据,不参与授权$allow 白名单,被拒参数显式报错而不是静默丢弃AdminPermission::demoCheck()(演示站禁止写操作)并 Admin::addInfoLog() 记录审计admin-cli-key 请求头凭证,避免凭证出现在 URL / 请求体 / 访问日志中;CLI 请求完全无状态(array session driver,不写会话、不下发 Cookie),后台面板 Cookie 不能单独访问 CLI 接口完整的 CLI 接口开发规范(三件套同步、凭证授权、脱敏、写白名单、测试要求)见 .agents/doc/cli.md。
adminUserId,不依赖 Session / CookieCliCrud::paginateModel)自动剔除 password / passwordSalt / token / openid / apikey 等敏感字段,敏感模块可传字段白名单$allow 时,金额、状态、统计字段不允许写入;客户端显式传入被拒字段会直接返回「不允许通过 CLI 写入」错误,不会静默忽略MemberUtil 的唯一性校验与密码加密;会员 API Key 由服务端生成且列表不返回明文MemberApiKey、PayUnifiedClient)在 api.json 中标记 founderOnly:中间件强制校验创始人身份,非创始人的 api_list 也不会展示这些接口api list 发现接口,再 call 执行