mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-30 12:45:32 +08:00
feat(mcp): 密钥授权页,仅创建者拥有的节点可授权(防越权与漂移)
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
namespace base\admin\controller\system;
|
||||
|
||||
use app\admin\model\SystemAdmin;
|
||||
use app\admin\model\SystemMcpKeyNode;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnotation;
|
||||
use app\admin\service\NodeService;
|
||||
use app\common\controller\AdminController;
|
||||
use app\common\service\AuthService;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
@@ -139,4 +142,120 @@ class McpKeyBase extends AdminController
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权页:勾选创建者当前权限的子集给密钥.
|
||||
* @NodeAnotation(title="授权")
|
||||
*/
|
||||
public function authorize($id)
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
|
||||
// 全量动作节点来自 getNodeTree 展开全部 type=2 节点
|
||||
$nodeService = new NodeService();
|
||||
$module_list = $nodeService->getNodeTree();
|
||||
|
||||
// 创建者当前节点集合:与 checkNode 完全一致的判定链(含超管直通/auth_on/动态黑名单)
|
||||
$authService = new AuthService($row->bind_admin_id);
|
||||
$allActionNodes = [];
|
||||
foreach ($module_list as $module) {
|
||||
foreach ($module['children'] as $controller) {
|
||||
foreach ($controller['children'] as $action) {
|
||||
$allActionNodes[] = $action['node'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$creatorAllowedNodes = $authService->getAdminAllowedNodes($allActionNodes, $row->bind_admin_id);
|
||||
|
||||
// 已选节点 = 库中记录 ∩ 创建者当前集合(防漂移:创建者权限被回收后旧勾选自动失效)
|
||||
$checkedNodeList = (new SystemMcpKeyNode())
|
||||
->where('key_id', $id)
|
||||
->column('node');
|
||||
$checkedNodeList = array_values(array_intersect($checkedNodeList, $creatorAllowedNodes));
|
||||
|
||||
// 树过滤:动作节点不在创建者集合内整级剔除;无动作节点的控制器、无控制器的模块不显示
|
||||
foreach ($module_list as $module_key => $module) {
|
||||
foreach ($module['children'] as $controllerKey => $controller) {
|
||||
foreach ($controller['children'] as $actionKey => $action) {
|
||||
if (!in_array($action['node'], $creatorAllowedNodes)) {
|
||||
unset($module_list[$module_key]['children'][$controllerKey]['children'][$actionKey]);
|
||||
continue;
|
||||
}
|
||||
$checked = in_array($action['node'], $checkedNodeList);
|
||||
$checked_string = $checked ? 'checked' : '';
|
||||
$disabled_string = '';
|
||||
if (!$action['auth']) {
|
||||
// 免鉴权节点创建者恒有权限,照 auth/authorize 惯例固定勾选并禁用
|
||||
$checked_string = 'checked';
|
||||
$disabled_string = 'disabled';
|
||||
}
|
||||
$module_list[$module_key]['children'][$controllerKey]['children'][$actionKey]['checked'] = $checked_string;
|
||||
$module_list[$module_key]['children'][$controllerKey]['children'][$actionKey]['disabled'] = $disabled_string;
|
||||
}
|
||||
if (empty($module_list[$module_key]['children'][$controllerKey]['children'])) {
|
||||
unset($module_list[$module_key]['children'][$controllerKey]);
|
||||
}
|
||||
}
|
||||
if (empty($module_list[$module_key]['children'])) {
|
||||
unset($module_list[$module_key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assign('row', $row);
|
||||
$this->assign('checked_node_list', $checkedNodeList);
|
||||
$this->assign('module_list', array_values($module_list));
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权保存:先删后插,服务端强校验防越权.
|
||||
* @NodeAnotation(title="授权保存")
|
||||
*/
|
||||
public function saveAuthorize()
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
$id = $this->request->post('id');
|
||||
$node = (array) $this->request->post('node', []);
|
||||
|
||||
$row = $this->model->find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
|
||||
// 服务端强校验:每个提交节点必须 ∈ 创建者当前节点集合(重新计算,防权限已变)
|
||||
$nodeService = new NodeService();
|
||||
$allActionNodes = [];
|
||||
foreach ($nodeService->getNodeTree() as $module) {
|
||||
foreach ($module['children'] as $controller) {
|
||||
foreach ($controller['children'] as $action) {
|
||||
$allActionNodes[] = $action['node'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$authService = new AuthService($row->bind_admin_id);
|
||||
$creatorAllowedNodes = $authService->getAdminAllowedNodes($allActionNodes, $row->bind_admin_id);
|
||||
foreach ($node as $vo) {
|
||||
if (!in_array($authService->parseNodeStr($vo), $creatorAllowedNodes)) {
|
||||
$this->error('包含无权限节点');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$keyNode = new SystemMcpKeyNode();
|
||||
$keyNode->where('key_id', $id)->delete();
|
||||
if (!empty($node)) {
|
||||
$saveAll = [];
|
||||
foreach ($node as $vo) {
|
||||
$saveAll[] = [
|
||||
'key_id' => $id,
|
||||
'node' => $authService->parseNodeStr($vo),
|
||||
];
|
||||
}
|
||||
$keyNode->saveAll($saveAll);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->error('保存失败');
|
||||
}
|
||||
$this->success('保存成功');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user