From deb71875c150cef98a7c6d2182c3048085a7f08f Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Wed, 30 Sep 2026 22:58:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(users):=20=E8=87=AA=E5=B7=B1=E5=8F=AF?= =?UTF-8?q?=E6=94=B9=E6=98=BE=E7=A4=BA=E5=90=8D=E3=80=81=E8=B6=85=E7=AE=A1?= =?UTF-8?q?=E5=8F=AF=E5=9C=A8=E7=BC=96=E8=BE=91=E9=87=8C=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E8=B6=85=E7=AE=A1=EF=BC=88=E4=BF=AE=E3=80=8C=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5/=E7=A6=81=E6=AD=A2=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=87=AA=E5=B7=B1=E7=9A=84=E8=B4=A6=E6=88=B7=E3=80=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 站长反馈:在 admin 模式下仍无法修改用户信息,弹「禁止在用户管理中修改自己的账户」; 另外角色下拉里没有「技术运维」。 1) 自己改自己:原来一律禁止 → 现在**只允许改姓名(显示名)**,其余(账号名/年级/班级/ 状态/角色/密码)只要动了就仍然拒绝。这样站长能在「用户管理」里把 admin 的显示名 改成自己的名字(登录名仍是 admin,应急登录不受影响)。 状态比较忽略大小写:库里是 active,客户端历史版本可能发 ACTIVE,不该因此判定"改了状态"。 2) 超管可在通用编辑接口里把别人提升为 SUPER_ADMIN(站长要求下拉里要有「技术运维」): 新增 allowPromoteBySuper 例外 —— 仅当登录者是 SUPER_ADMIN、目标角色设为 SUPER_ADMIN、 且目标不是初始账号(ID=1,本来就是超管)时放行;非超管仍被 canChangeRoleOf 拦住。 与 POST /api/admin/users/{id}/promote-super 效果一致,两条路都能走。 --- server/api/admin/users/[id].put.ts | 38 +++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/server/api/admin/users/[id].put.ts b/server/api/admin/users/[id].put.ts index 9825c1b..f65cf5b 100644 --- a/server/api/admin/users/[id].put.ts +++ b/server/api/admin/users/[id].put.ts @@ -109,12 +109,29 @@ export default defineEventHandler(async (event) => { } } - // 2. 禁止对自身进行任何用户管理操作(包括角色、资料、状态、密码等) + /* + * 2. 自己改自己:**只允许改姓名(显示名)**,其余一律禁止。 + * + * 站长要在「用户管理」里把 admin 的显示名改成自己的名字(登录名仍是 admin), + * 原来这里是"自己一律不能改",于是他只看到「禁止在用户管理中修改自己的账户」。 + * 放宽到"只有姓名变了、其它字段一个都没动"是安全的:改不了角色/状态/密码/账号名, + * 也提不了权,只是换个显示名而已(等价于个人资料页改名字)。 + */ if (String(userId) === String(user.id)) { - throw createError({ - statusCode: 400, - statusMessage: '禁止在用户管理中修改自己的账户' - }) + const gradeChanged = String(grade || '').trim() !== String(targetUser.grade || '').trim() + const classChanged = String(userClass || '').trim() !== String(targetUser.class || '').trim() + const statusChanged = + !!status && String(status).toLowerCase() !== String(targetUser.status || '').toLowerCase() + const roleChanged = !!role && role !== targetUser.role + const onlyNameChanged = + nameChanged && !usernameChanged && !gradeChanged && !classChanged && !statusChanged && !roleChanged && !password + + if (!onlyNameChanged) { + throw createError({ + statusCode: 400, + statusMessage: '禁止在用户管理中修改自己的账户(自己只能改「姓名」,其它请到「设置」里操作)' + }) + } } // 3. 非超级管理员必须严格高于目标角色级别 @@ -144,7 +161,16 @@ export default defineEventHandler(async (event) => { // 角色权限控制(统一使用 canChangeRoleOf 语义化检查) let validRole = targetUser.role if (role && role !== targetUser.role) { - if (!canChangeRoleOf(user, targetUser, role)) { + /* + * 站长要求用户编辑表单的角色下拉里要有「技术运维」(SUPER_ADMIN)。 + * 原 canChangeRoleOf() 一律禁止提升为 SUPER_ADMIN(网页版也这么设计), + * 这里对**超级管理员**放开这一条:只有超管能把别人提升为超管,且目标不能是初始账号(ID=1,它本来就是)。 + * 效果与 POST /api/admin/users/{id}/promote-super 一致,两条路都可用。 + */ + const allowPromoteBySuper = + user.role === 'SUPER_ADMIN' && role === 'SUPER_ADMIN' && targetUser.id !== 1 + + if (!allowPromoteBySuper && !canChangeRoleOf(user, targetUser, role)) { throw createError({ statusCode: 403, statusMessage: user.role === 'SUPER_ADMIN'