站长诉求:想自定义 admin 账号的资料,但**必须保留 admin/admin123 作为应急登录**;
同时想用自己绑了微信的中文账号做日常管理。
按"哪些能改、哪些必须锁死"拆开处理:
1) server/api/admin/users/[id].put.ts —— 原来对 ID=1 **一律 403**(连显示名都改不了),
现在:
· 允许改:姓名(显示名)、年级、班级、状态;
· 锁死:登录名必须保持 admin(那就是 admin/admin123 的应急通道,改了就登不进去);
· 锁死:角色不能动(防止把自己降权导致没人能管站点);
· 锁死:密码不在这里改(避免被其它管理员顺手重置;要改用它登录后去「设置」里改)。
2) 新增 POST /api/admin/users/{id}/promote-super —— 把某个账号提升为超级管理员。
之所以单开接口而不是放开通用编辑接口的 role:原 `canChangeRoleOf()` 明确禁止提升为
SUPER_ADMIN,两个前端的角色下拉也故意不给这一项。这里是**显式、可审计**的通道:
仅 SUPER_ADMIN 可调、不能提升自己、已经是超管的会提示、成功后清该用户认证缓存。
前端(小程序)配套:用户管理操作菜单改成 {label, run} 数组(有权限时才出现"提升为超级管理员",
不再靠写死 tapIndex),点击有二次确认并列出会拿到的权限;编辑初始管理员时登录名输入框 disabled
并显示原因,姓名照常可改。
67 lines
2.9 KiB
TypeScript
67 lines
2.9 KiB
TypeScript
import { eq } from 'drizzle-orm'
|
|
import { db } from '~/drizzle/db'
|
|
import { users } from '~/drizzle/schema'
|
|
import { getRoleLevel } from '~~/server/utils/permissions'
|
|
|
|
/**
|
|
* 把某个账号**提升为超级管理员**(第 90 轮新增)。
|
|
*
|
|
* 为什么单独开一个接口,而不是放开 `[id].put.ts` 的 role 字段:
|
|
* 那里面 `canChangeRoleOf()` **明确禁止**把任何人提升为 SUPER_ADMIN
|
|
* (报错原文:"超级管理员不能将目标用户提升为 SUPER_ADMIN"),
|
|
* 而且用户管理的角色下拉也**故意不给** SUPER_ADMIN 选项(网页版同样如此)。
|
|
* 站长的诉求是"用我自己绑了微信的中文账号做日常管理",所以要给一条**显式、可审计**的通道:
|
|
* 单独接口 + 前端二次确认,而不是把通用编辑接口的口子放大。
|
|
*
|
|
* 权限:只有 SUPER_ADMIN 能调;不能提升自己(已经是了);不能对已经是超管的账号重复提升。
|
|
* 注意:初始超级管理员(ID=1)本身就是 SUPER_ADMIN,会命中"已经是超级管理员"。
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
const user = event.context.user
|
|
if (!user) {
|
|
throw createError({ statusCode: 401, message: '未登录' })
|
|
}
|
|
if (user.role !== 'SUPER_ADMIN') {
|
|
throw createError({ statusCode: 403, message: '仅超级管理员可以提升其他账号为超级管理员' })
|
|
}
|
|
|
|
const userId = Number(getRouterParam(event, 'id'))
|
|
if (!userId || Number.isNaN(userId)) {
|
|
throw createError({ statusCode: 400, message: '无效的用户ID' })
|
|
}
|
|
if (userId === user.id) {
|
|
throw createError({ statusCode: 400, message: '你自己已经是超级管理员了' })
|
|
}
|
|
|
|
const rows = await db.select().from(users).where(eq(users.id, userId)).limit(1)
|
|
if (rows.length === 0) {
|
|
throw createError({ statusCode: 404, message: '用户不存在' })
|
|
}
|
|
const target = rows[0]
|
|
|
|
if (target.role === 'SUPER_ADMIN') {
|
|
throw createError({ statusCode: 400, message: `「${target.name || target.username}」已经是超级管理员` })
|
|
}
|
|
// 只允许"向上提升",不允许借此降权(降权仍走通用编辑接口)
|
|
if (getRoleLevel(target.role) > getRoleLevel('SUPER_ADMIN')) {
|
|
throw createError({ statusCode: 400, message: '目标账号角色异常,无法提升' })
|
|
}
|
|
|
|
await db.update(users).set({ role: 'SUPER_ADMIN' }).where(eq(users.id, userId))
|
|
|
|
// 角色变了 → 清掉它的认证缓存,避免旧权限继续生效
|
|
try {
|
|
const { cache } = await import('~~/server/utils/cache-helpers')
|
|
await cache.delete(`auth:user:${userId}`)
|
|
} catch {
|
|
// 清缓存失败不影响提升结果
|
|
}
|
|
|
|
console.log(`[Users] ${user.username} 把 ${target.username}(#${userId}) 提升为 SUPER_ADMIN`)
|
|
return {
|
|
success: true,
|
|
message: `已把「${target.name || target.username}」提升为超级管理员`,
|
|
user: { id: target.id, name: target.name, username: target.username, role: 'SUPER_ADMIN' }
|
|
}
|
|
})
|