53 lines
3.7 KiB
JavaScript
53 lines
3.7 KiB
JavaScript
// 用户管理审计:角色 / 列表 / 新建 / 重置密码 / 删除 / 越权防护
|
|
const BASE = process.env.SYNC_BASE || 'http://127.0.0.1:3780'
|
|
let pass = 0, fail = 0
|
|
function check(name, ok, detail) {
|
|
if (ok) { pass++; console.log(' PASS ' + name) }
|
|
else { fail++; console.log(' FAIL ' + name + (detail ? ' -> ' + String(JSON.stringify(detail)).slice(0, 160) : '')) }
|
|
}
|
|
async function req(path, method, body, token) {
|
|
const r = await fetch(BASE + path, {
|
|
method,
|
|
headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: 'Bearer ' + token } : {}) },
|
|
body: body ? JSON.stringify(body) : undefined
|
|
})
|
|
return { status: r.status, data: await r.json().catch(() => ({})) }
|
|
}
|
|
async function main() {
|
|
const ax = await req('/api/auth/register', 'POST', { username: 'xionglin', password: 'admin123' })
|
|
check('xionglin 注册成功', ax.status === 200, ax.data)
|
|
const nu = await req('/api/auth/register', 'POST', { username: 'normal_u', password: 'normal123' })
|
|
check('普通用户注册成功', nu.status === 200, nu.data)
|
|
const listNoAuth = await req('/api/admin/users', 'GET', null, nu.data.token)
|
|
check('非管理员访问用户列表 403', listNoAuth.status === 403, listNoAuth.status)
|
|
const badList = await req('/api/admin/users', 'GET', null)
|
|
check('无 token 访问用户列表 403', badList.status === 403, badList.status)
|
|
const list = await req('/api/admin/users', 'GET', null, ax.data.token)
|
|
check('管理员可见用户列表', list.status === 200 && ((list.data.users || []).some(u => u.username === 'normal_u') && (list.data.users.some(u => u.username === 'xionglin' && u.role === 'admin'))), list.data)
|
|
check('列表返回 me 字段', !!list.data.me)
|
|
const create = await req('/api/admin/users/create', 'POST', { username: 'target_u', password: 'pass111' }, ax.data.token)
|
|
check('管理员新建用户', create.status === 200 && !!create.data.userId, create.data)
|
|
const dupCreate = await req('/api/admin/users/create', 'POST', { username: 'target_u', password: 'pass222' }, ax.data.token)
|
|
check('重复用户名 409', dupCreate.status === 409, dupCreate.status)
|
|
const loginTarget = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass111' })
|
|
check('新用户可用初始密码登录', loginTarget.status === 200, loginTarget.status)
|
|
const reset = await req('/api/admin/users/password', 'POST', { userId: create.data.userId, newPassword: 'pass999' }, ax.data.token)
|
|
check('管理员重置密码 200', reset.status === 200, reset.data)
|
|
const oldLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass111' })
|
|
check('旧密码失效 401', oldLogin.status === 401, oldLogin.status)
|
|
const newLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass999' })
|
|
check('重置后新密码可登录', newLogin.status === 200, newLogin.status)
|
|
const selfDel = await req('/api/admin/users/delete', 'POST', { userId: ax.data.userId }, ax.data.token)
|
|
check('不能删除自己 400', selfDel.status === 400, selfDel.status)
|
|
const del = await req('/api/admin/users/delete', 'POST', { userId: create.data.userId }, ax.data.token)
|
|
check('删除用户 200', del.status === 200, del.data)
|
|
const goneLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass999' })
|
|
check('删除后登录被拒 401', goneLogin.status === 401, goneLogin.status)
|
|
const list2 = await req('/api/admin/users', 'GET', null, ax.data.token)
|
|
check('列表不再含已删用户', !((list2.data.users || []).some(u => u.username === 'target_u')))
|
|
|
|
console.log('==== 用户管理审计: PASS ' + pass + ' / FAIL ' + fail + ' ====')
|
|
process.exit(fail > 0 ? 1 : 0)
|
|
}
|
|
main().catch(e => { console.error('FAILED:', e && (e.stack || e.message)); process.exit(1) })
|