fix(admin): remove email reauth from account reset
This commit is contained in:
@@ -2869,3 +2869,18 @@
|
||||
- 防复发:任何测试创建本地数据客户端必须在 `fixture.stop()` 之前按自身 service URL 关闭连接池;测试不得用 `identity_runtime` 向 `public.*` 播种 fixture 行(一律走 postgres admin 的 `fixture.psql`);禁止为测试放宽运行时 grant 或改迁移。
|
||||
- 相关记录:BUG-163、BUG-164、BUG-165
|
||||
- 修复版本:本地 staging 候选(未 push / deploy)
|
||||
|
||||
## BUG-167 | 管理端账号重置重复要求邮箱验证码
|
||||
|
||||
- 状态:resolved(本地验证通过,待 staging 部署验收)
|
||||
- 首次发现:2026-08-11
|
||||
- 最近更新:2026-08-11
|
||||
- 影响面:管理端用户列表“重置资料与会话”弹窗与 `POST /api/admin/customers/reset`
|
||||
- 用户现象:已登录且具备账号管理权限的管理员执行账号重置时,仍需额外发送并输入邮箱验证码,增加不必要的操作步骤。
|
||||
- 触发条件:在用户列表打开重置弹窗并提交账号重置。
|
||||
- 根因:账号重置复用了面向角色变更、账务调整等操作的 `requireHighRiskAdminMutation` 与 `reauthPermission`,把一次性邮箱复核错误扩展到了已有登录、权限、原因、可信来源及数据库审计保护的重置路径。
|
||||
- 修复:该路由改用既有 `requireAdminMutation(request, "admin.users.manage_roles")`,前端仅移除该弹窗的 `reauthPermission`;保留管理员会话、权限、可信 Origin、确认字面量、操作原因、数据库权限检查与审计日志。其他高风险管理员操作继续使用邮箱复核。
|
||||
- 验证:账号重置合同测试确认前后端均不再要求邮箱复核,同时管理员角色变更仍使用 `requireHighRiskAdminMutation`;管理端 Origin 与授权边界的既有测试继续覆盖未登录 `401`、缺少权限/不可信来源 `403`。
|
||||
- 防复发:账号重置只允许使用普通管理员 mutation guard;共享高风险 guard 不做全局放松,并由合同测试锁定角色变更仍需邮箱复核。
|
||||
- 相关记录:无
|
||||
- 修复版本:本次 staging 候选
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
adminErrorResponse,
|
||||
invalidQueryResponse,
|
||||
requestId,
|
||||
requireHighRiskAdminMutation,
|
||||
requireAdminMutation,
|
||||
} from "@/lib/admin/http";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
@@ -28,7 +28,7 @@ type ResetRow = {
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const session = await requireHighRiskAdminMutation(
|
||||
const session = await requireAdminMutation(
|
||||
request,
|
||||
"admin.users.manage_roles",
|
||||
);
|
||||
|
||||
@@ -133,7 +133,6 @@ export default function UsersPage() {
|
||||
okText="确认重置"
|
||||
danger
|
||||
confirmLoading={resetting}
|
||||
reauthPermission="admin.users.manage_roles"
|
||||
onCancel={() => setResetTarget(null)}
|
||||
onSubmit={resetAccount}
|
||||
/>
|
||||
|
||||
@@ -6,14 +6,17 @@ const root = new URL("../", import.meta.url);
|
||||
const route = readFileSync(new URL("src/app/api/admin/customers/reset/route.ts", root), "utf8");
|
||||
const users = readFileSync(new URL("src/components/admin/users-resource.tsx", root), "utf8");
|
||||
const migration = readFileSync(new URL("supabase/migrations/20260811020000_admin_customer_account_reset.sql", root), "utf8");
|
||||
const administratorsRoute = readFileSync(new URL("src/app/api/admin/administrators/route.ts", root), "utf8");
|
||||
|
||||
test("admin account reset stays owner-only, explicit, and high risk", () => {
|
||||
assert.match(route, /requireHighRiskAdminMutation\(\s*request,\s*"admin\.users\.manage_roles",?\s*\)/);
|
||||
test("admin account reset stays owner-only and explicit without email reauth", () => {
|
||||
assert.match(route, /requireAdminMutation\(\s*request,\s*"admin\.users\.manage_roles",?\s*\)/);
|
||||
assert.doesNotMatch(route, /requireHighRiskAdminMutation/);
|
||||
assert.match(route, /confirmation:\s*z\.literal\("RESET"\)/);
|
||||
assert.match(route, /admin_reset_customer_account\(\$1, \$2, \$3, \$4\)/);
|
||||
assert.match(users, /permissions\.includes\("admin\.users\.manage_roles"\)/);
|
||||
assert.match(users, /reauthPermission="admin\.users\.manage_roles"/);
|
||||
assert.doesNotMatch(users, /reauthPermission=/);
|
||||
assert.match(users, /登录身份、管理员角色、积分及账务审计记录会保留/);
|
||||
assert.match(administratorsRoute, /requireHighRiskAdminMutation\(\s*request,\s*"admin\.users\.manage_roles",?\s*\)/);
|
||||
});
|
||||
|
||||
test("database reset mirrors the existing staging reset boundary and audits it", () => {
|
||||
|
||||
Reference in New Issue
Block a user