diff --git a/app/admin/controller/auth/Admin.php b/app/admin/controller/auth/Admin.php index 8ab0762..c5ca548 100644 --- a/app/admin/controller/auth/Admin.php +++ b/app/admin/controller/auth/Admin.php @@ -21,7 +21,10 @@ class Admin extends Backend protected array|string $quickSearchField = ['username', 'nickname']; - protected string|int|bool $dataLimit = 'allAuthAndOthers'; + /** + * 开启数据范围;具体范围见重写的 getDataLimitAdminIds(角色组树:仅本人 + 下级组内管理员) + */ + protected bool|string|int $dataLimit = true; protected string $dataLimitField = 'id'; @@ -31,6 +34,17 @@ class Admin extends Backend return null; } + /** + * 非超管:仅可管理「本人 + 树形下级组内」的管理员账号;与角色组管理页的可见范围一致(列表不含仅同级的其他管理员) + */ + protected function getDataLimitAdminIds(): array + { + if (!$this->dataLimit || !$this->auth || $this->auth->isSuperAdmin()) { + return []; + } + return $this->auth->getSelfAndSubordinateAdminIds(); + } + public function index(Request $request): Response { $response = $this->initializeBackend($request); @@ -357,9 +371,12 @@ class Admin extends Backend if ($this->auth->isSuperAdmin()) { return null; } - $authGroups = $this->auth->getAllAuthGroups('allAuthAndOthers'); + $allowedGroupIds = array_values(array_unique(array_merge( + Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'), + $this->auth->getAdminChildGroups() + ))); foreach ($groups as $group) { - if (!in_array($group, $authGroups)) { + if (!in_array($group, $allowedGroupIds, false)) { return $this->error(__('You have no permission to add an administrator to this group!')); } } diff --git a/app/admin/controller/auth/AdminLog.php b/app/admin/controller/auth/AdminLog.php index 1bee893..7d0e599 100644 --- a/app/admin/controller/auth/AdminLog.php +++ b/app/admin/controller/auth/AdminLog.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace app\admin\controller\auth; -use Throwable; use app\common\controller\Backend; use app\admin\model\AdminLog as AdminLogModel; use support\Response; @@ -36,7 +35,10 @@ class AdminLog extends Backend list($where, $alias, $limit, $order) = $this->queryBuilder(); if (!$this->auth->isSuperAdmin()) { - $where[] = ['admin_id', '=', $this->auth->id]; + $scopeIds = $this->auth->getSelfAndSubordinateAdminIds(); + if ($scopeIds !== []) { + $where[] = ['admin_id', 'in', $scopeIds]; + } } $res = $this->model ->withJoin($this->withJoinTable, $this->withJoinType) diff --git a/app/admin/controller/auth/Group.php b/app/admin/controller/auth/Group.php index 26cb0ec..dabe9f2 100644 --- a/app/admin/controller/auth/Group.php +++ b/app/admin/controller/auth/Group.php @@ -17,8 +17,6 @@ use Webman\Http\Request; class Group extends Backend { - protected string $authMethod = 'allAuthAndOthers'; - protected ?object $model = null; protected string|array $preExcludeFields = ['create_time', 'update_time']; @@ -82,6 +80,9 @@ class Group extends Backend $rulesRes = $this->handleRules($data); if ($rulesRes instanceof Response) return $rulesRes; + $pidRes = $this->validateGroupParentId($data['pid'] ?? null); + if ($pidRes instanceof Response) return $pidRes; + $result = false; $this->model->startTrans(); try { @@ -144,6 +145,11 @@ class Group extends Backend $rulesRes = $this->handleRules($data); if ($rulesRes instanceof Response) return $rulesRes; + if (array_key_exists('pid', $data)) { + $pidRes = $this->validateGroupParentId($data['pid'] ?? null); + if ($pidRes instanceof Response) return $pidRes; + } + $result = false; $this->model->startTrans(); try { @@ -294,8 +300,6 @@ class Group extends Backend $pk = $this->model->getPk(); $initKey = $request->get('initKey') ?? $pk; - $absoluteAuth = $request->get('absoluteAuth') ?? false; - if ($this->keyword) { $keyword = explode(' ', $this->keyword); foreach ($keyword as $item) { @@ -308,11 +312,14 @@ class Group extends Backend } if (!$this->auth->isSuperAdmin()) { - $authGroups = $this->auth->getAllAuthGroups($this->authMethod, $where); - if (!$absoluteAuth) { - $authGroups = array_merge($this->adminGroups, $authGroups); + $descendantIds = $this->auth->getAdminChildGroups(); + // 本人所在组 + 树形下级;不含同级、不含其它分支(与 getAllAuthGroups 的「权限多寡」脱钩) + $visibleIds = array_values(array_unique(array_merge($this->adminGroups, $descendantIds))); + if ($visibleIds === []) { + $where[] = ['id', '=', -1]; + } else { + $where[] = ['id', 'in', $visibleIds]; } - $where[] = ['id', 'in', $authGroups]; } $data = $this->model->where($where)->select()->toArray(); @@ -337,9 +344,43 @@ class Group extends Backend private function checkAuth($groupId): ?Response { - $authGroups = $this->auth->getAllAuthGroups($this->authMethod, []); - if (!$this->auth->isSuperAdmin() && !in_array($groupId, $authGroups)) { - return $this->error(__($this->authMethod == 'allAuth' ? 'You need to have all permissions of this group to operate this group~' : 'You need to have all the permissions of the group and have additional permissions before you can operate the group~')); + if ($this->auth->isSuperAdmin()) { + return null; + } + $descendantIds = $this->auth->getAdminChildGroups(); + if (!in_array($groupId, $descendantIds, false)) { + return $this->error(__('You can only operate subordinate role groups in the tree hierarchy~')); + } + return null; + } + + /** + * 新增/编辑时校验父级:非超管只能挂在本人所在组或其树形下级之下,不可建顶级(pid=0) + */ + private function validateGroupParentId(mixed $pid): ?Response + { + if ($this->auth->isSuperAdmin()) { + return null; + } + if ($pid === null || $pid === '' || $pid === false) { + return $this->error(__('Non super administrators cannot create top-level role groups')); + } + if ($pid === 0 || $pid === '0') { + return $this->error(__('Non super administrators cannot create top-level role groups')); + } + if (!is_numeric($pid)) { + return $this->error(__('The parent group is not within your manageable scope')); + } + $allowed = array_values(array_unique(array_merge($this->adminGroups, $this->auth->getAdminChildGroups()))); + $ok = false; + foreach ($allowed as $aid) { + if ($aid == $pid) { + $ok = true; + break; + } + } + if (!$ok) { + return $this->error(__('The parent group is not within your manageable scope')); } return null; } diff --git a/app/admin/lang/en/auth/group.php b/app/admin/lang/en/auth/group.php index 1a80451..a05132b 100644 --- a/app/admin/lang/en/auth/group.php +++ b/app/admin/lang/en/auth/group.php @@ -9,5 +9,8 @@ return [ 'You need to have all the permissions of the group and have additional permissions before you can operate the group~' => 'You need to have all the permissions of the group and have additional permissions before you can operate the group~', 'Role group has all your rights, please contact the upper administrator to add or do not need to add!' => 'Role group has all your rights, please contact the upper administrator to add or do not need to add!', 'The group permission node exceeds the range that can be allocated' => 'The group permission node exceeds the range that can be allocated, please refresh and try again~', - 'Remark lang' => 'For system security, the hierarchical relationship of role groups is for reference only. The actual hierarchy is determined by the number of permission nodes: same permissions = peer, containing and having additional permissions = superior. Peers cannot manage peers; superiors can assign their permission nodes to subordinates. For special cases where an admin needs to become a superior, create a virtual permission node.', + 'You can only operate subordinate role groups in the tree hierarchy~' => 'You can only manage role groups that are strictly below yours in the role-group tree (not peers or other branches).', + 'Non super administrators cannot create top-level role groups' => 'Non super administrators cannot create top-level role groups', + 'The parent group is not within your manageable scope' => 'The selected parent group is outside your manageable scope', + 'Remark lang' => 'Role groups follow the tree (parent/child): you may only manage groups under your own membership branch; peers, other branches and ancestors cannot be managed here. When assigning rules you can still only select permission nodes you own.', ]; diff --git a/app/admin/lang/zh-cn/auth/group.php b/app/admin/lang/zh-cn/auth/group.php index 1b5db16..f4a6a19 100644 --- a/app/admin/lang/zh-cn/auth/group.php +++ b/app/admin/lang/zh-cn/auth/group.php @@ -9,5 +9,8 @@ return [ 'You need to have all the permissions of the group and have additional permissions before you can operate the group~' => '您需要拥有该分组的所有权限且还有额外权限时,才可以操作该分组~', 'Role group has all your rights, please contact the upper administrator to add or do not need to add!' => '角色组拥有您的全部权限,请联系上级管理员添加或无需添加!', 'The group permission node exceeds the range that can be allocated' => '分组权限节点超出可分配范围,请刷新重试~', - 'Remark lang' => '为保障系统安全,角色组本身的上下级关系仅供参考,系统的实际上下级划分是根据`权限多寡`来确定的,两位管理员的权限节点:相同被认为是`同级`、包含且有额外权限才被认为是`上级`,同级不可管理同级,上级可为下级分配自己拥有的权限节点;若有特殊情况管理员需转`上级`,可建立一个虚拟权限节点', + 'You can only operate subordinate role groups in the tree hierarchy~' => '仅可管理在角色组树中属于您下级的角色组(不含同级、不含其他分支)~', + 'Non super administrators cannot create top-level role groups' => '非超级管理员不能创建顶级角色组', + 'The parent group is not within your manageable scope' => '所选父级角色组不在您可管理的范围内', + 'Remark lang' => '角色组以「树形父子关系」为准:仅可管理本人所在组之下的下级组;同级、其他分支及上级组不可在此管理。分配权限时仍只能勾选您自身拥有的权限节点。', ]; diff --git a/app/admin/library/Auth.php b/app/admin/library/Auth.php index 97c8e07..db20ffa 100644 --- a/app/admin/library/Auth.php +++ b/app/admin/library/Auth.php @@ -297,6 +297,26 @@ class Auth extends \ba\Auth return array_unique($children); } + /** + * 本人 + 树形下级角色组内的管理员 ID(与管理员管理列表数据范围一致) + */ + public function getSelfAndSubordinateAdminIds(): array + { + if ($this->isSuperAdmin()) { + return []; + } + $descendantGroupIds = $this->getAdminChildGroups(); + $adminIds = []; + if ($descendantGroupIds !== []) { + $adminIds = Db::name('admin_group_access') + ->where('group_id', 'in', $descendantGroupIds) + ->column('uid'); + } + $adminIds[] = $this->id; + + return array_values(array_unique($adminIds)); + } + public function getGroupChildGroups(int $groupId, array &$children): void { $childrenTemp = AdminGroup::where('pid', $groupId) diff --git a/web/src/lang/backend/en/auth/group.ts b/web/src/lang/backend/en/auth/group.ts index 57f8a04..a03327c 100644 --- a/web/src/lang/backend/en/auth/group.ts +++ b/web/src/lang/backend/en/auth/group.ts @@ -5,5 +5,5 @@ export default { 'Parent group': 'Superior group', 'The parent group cannot be the group itself': 'The parent group cannot be the group itself', 'Manage subordinate role groups here': - 'In managing a subordinate role group (excluding a peer role group), you have all the rights of a subordinate role group and additional rights', + 'You can only manage role groups under your branch in the tree; peers, other branches and ancestors are out of scope. You can still only assign permission nodes you own.', } diff --git a/web/src/lang/backend/zh-cn/auth/group.ts b/web/src/lang/backend/zh-cn/auth/group.ts index 18f6a82..28befd6 100644 --- a/web/src/lang/backend/zh-cn/auth/group.ts +++ b/web/src/lang/backend/zh-cn/auth/group.ts @@ -4,5 +4,6 @@ export default { jurisdiction: '权限', 'Parent group': '上级分组', 'The parent group cannot be the group itself': '上级分组不能是分组本身', - 'Manage subordinate role groups here': '在此管理下级角色组(您拥有下级角色组的所有权限并且拥有额外的权限,不含同级)', + 'Manage subordinate role groups here': + '在此仅可管理「角色组树」中您所在组之下的下级组;同级、其他分支与上级组不在管理范围内。分配权限时仍只能勾选您自身拥有的节点。', }