Admin:管理员自助修改密码 #57

Closed
opened 2026-08-09 16:39:25 +08:00 by ila · 3 comments
Owner

基本信息

  • 状态:已完成
  • 类型:需求
  • 父级大工单:#14
  • 所属 MVP / 版本:#15 Admin 四模块可用闭环
  • 阶段:Admin 登录与最小账号管理

要解决什么

当前唯一管理员账号没有可见的密码修改入口。用户管理页只允许管理员重置采购员密码,管理员行显示“唯一管理员”,因此管理员无法通过正常界面主动更换自己的密码。

目标是在已登录 Admin 的公共顶部区域提供管理员自助修改密码能力,并用当前密码校验防止已登录页面被他人短暂接触时直接夺取账号。

做什么 / 不做什么

  • 做:仅向已登录管理员显示“修改密码”入口。
  • 做:表单要求填写当前密码、新密码和确认新密码;新密码至少 6 个字符、最多 72 个字节。
  • 做:从当前 Session 取得用户身份,不接受表单传入目标用户 ID。
  • 做:当前密码正确且两次新密码一致后更新密码,并原子撤销该管理员的全部 Web Session。
  • 做:成功后清除当前浏览器 Session Cookie,跳转登录页并提示使用新密码重新登录。
  • 做:POST 写操作经过现有 CSRF 防护,错误信息不记录或回显密码。
  • 不做:不提供忘记密码/绕过当前密码的恢复入口。
  • 不做:不开放采购员自行修改密码,采购员继续由管理员重置。
  • 不做:不改变 Client 四接口、数据库结构、角色模型或真实下单行为。

怎么做

  1. 在公共顶部模板中为管理员增加“修改密码”按钮,并复用现有公共弹窗。
  2. 弹窗使用明确标签和帮助文字,当前密码使用 autocomplete="current-password",新密码使用 autocomplete="new-password";服务端错误回到页面并自动重新打开弹窗、聚焦首个需修正字段。
  3. 在 Web 路由中增加管理员权限保护的 POST /account/change-password,沿用页面组的认证和 CSRF 中间件。
  4. Handler 只读取表单和当前用户、调用 Service、清 Cookie 与重定向。
  5. Service 校验管理员身份、当前密码、新密码规则及确认值;Repository 在事务中以预期旧密码哈希为条件更新密码,并撤销该用户全部 Session,避免并发修改覆盖。
  6. 增加 Service、路由集成和模板回归测试;运行浏览器交互检查及 Go 1.23.0 全量验证。

预计修改:

  • admin/templates/partials/header.html
  • admin/static/css/app.css(仅在现有样式不足时)
  • admin/static/js/app.js(仅用于失败后打开/聚焦,复用公共弹窗)
  • admin/handler/web/auth.go
  • admin/handler/web/web.go
  • admin/service/auth.go
  • admin/repository/user.go
  • 对应测试文件
  • docs/admin/05-ui-specification.md
  • docs/admin/06-quality-security.md

不新增数据库迁移,不改变 Client API。

验收标准

  • 已登录管理员可从公共顶部入口打开修改密码弹窗;采购员看不到该入口。
  • 当前密码错误时拒绝修改,原密码和现有 Session 保持有效。
  • 新密码少于 6 个字符、超过 72 个字节或两次输入不一致时拒绝修改并给出明确修正提示。
  • 修改成功后旧密码无法登录,新密码可以登录。
  • 修改成功后该管理员全部 Web Session 被撤销,当前浏览器跳转登录页且 Session Cookie 被清除。
  • 请求不能指定或修改其他用户,采购员直接请求接口也被拒绝。
  • 无 CSRF 的修改请求返回 403,Client 四接口行为不变。
  • 密码不会出现在日志、页面响应、Gitea 工单或归档中。
  • 弹窗具备可见标签、密码自动填充语义、键盘焦点和可访问错误提示;拖选密码不会误关闭弹窗。
  • go vet ./...、go test ./... 及 Go 1.23.0 构建和无缓存测试通过。

怎么验证

从 admin/ 执行:

gofmt -w .
go vet ./...
go test ./...
$env:GOTOOLCHAIN="go1.23.0"
go build ./...
go test ./... -count=1
Remove-Item Env:GOTOOLCHAIN

浏览器验证:

  1. 管理员打开弹窗,分别验证错误当前密码、长度边界、确认不一致。
  2. 修改成功后确认跳回登录页,旧密码失败、新密码成功。
  3. 在另一个已登录浏览器中确认旧 Session 同时失效。
  4. 采购员登录后确认无入口,直接 POST 也被拒绝。

风险和回退

  • 风险:Session 撤销或 Cookie 清理遗漏会让旧会话继续可用;通过多 Session 集成测试覆盖。
  • 风险:更新密码与撤销 Session 若不原子,会出现新密码已生效但旧 Session 未撤销;两步必须放在同一事务。
  • 回退:回退本任务提交即可恢复原行为;无数据库迁移和数据结构回退。
## 基本信息 - 状态:已完成 - 类型:需求 - 父级大工单:#14 - 所属 MVP / 版本:#15 Admin 四模块可用闭环 - 阶段:Admin 登录与最小账号管理 ## 要解决什么 当前唯一管理员账号没有可见的密码修改入口。用户管理页只允许管理员重置采购员密码,管理员行显示“唯一管理员”,因此管理员无法通过正常界面主动更换自己的密码。 目标是在已登录 Admin 的公共顶部区域提供管理员自助修改密码能力,并用当前密码校验防止已登录页面被他人短暂接触时直接夺取账号。 ## 做什么 / 不做什么 - 做:仅向已登录管理员显示“修改密码”入口。 - 做:表单要求填写当前密码、新密码和确认新密码;新密码至少 6 个字符、最多 72 个字节。 - 做:从当前 Session 取得用户身份,不接受表单传入目标用户 ID。 - 做:当前密码正确且两次新密码一致后更新密码,并原子撤销该管理员的全部 Web Session。 - 做:成功后清除当前浏览器 Session Cookie,跳转登录页并提示使用新密码重新登录。 - 做:POST 写操作经过现有 CSRF 防护,错误信息不记录或回显密码。 - 不做:不提供忘记密码/绕过当前密码的恢复入口。 - 不做:不开放采购员自行修改密码,采购员继续由管理员重置。 - 不做:不改变 Client 四接口、数据库结构、角色模型或真实下单行为。 ## 怎么做 1. 在公共顶部模板中为管理员增加“修改密码”按钮,并复用现有公共弹窗。 2. 弹窗使用明确标签和帮助文字,当前密码使用 `autocomplete="current-password"`,新密码使用 `autocomplete="new-password"`;服务端错误回到页面并自动重新打开弹窗、聚焦首个需修正字段。 3. 在 Web 路由中增加管理员权限保护的 `POST /account/change-password`,沿用页面组的认证和 CSRF 中间件。 4. Handler 只读取表单和当前用户、调用 Service、清 Cookie 与重定向。 5. Service 校验管理员身份、当前密码、新密码规则及确认值;Repository 在事务中以预期旧密码哈希为条件更新密码,并撤销该用户全部 Session,避免并发修改覆盖。 6. 增加 Service、路由集成和模板回归测试;运行浏览器交互检查及 Go 1.23.0 全量验证。 预计修改: - `admin/templates/partials/header.html` - `admin/static/css/app.css`(仅在现有样式不足时) - `admin/static/js/app.js`(仅用于失败后打开/聚焦,复用公共弹窗) - `admin/handler/web/auth.go` - `admin/handler/web/web.go` - `admin/service/auth.go` - `admin/repository/user.go` - 对应测试文件 - `docs/admin/05-ui-specification.md` - `docs/admin/06-quality-security.md` 不新增数据库迁移,不改变 Client API。 ## 验收标准 - [x] 已登录管理员可从公共顶部入口打开修改密码弹窗;采购员看不到该入口。 - [x] 当前密码错误时拒绝修改,原密码和现有 Session 保持有效。 - [x] 新密码少于 6 个字符、超过 72 个字节或两次输入不一致时拒绝修改并给出明确修正提示。 - [x] 修改成功后旧密码无法登录,新密码可以登录。 - [x] 修改成功后该管理员全部 Web Session 被撤销,当前浏览器跳转登录页且 Session Cookie 被清除。 - [x] 请求不能指定或修改其他用户,采购员直接请求接口也被拒绝。 - [x] 无 CSRF 的修改请求返回 403,Client 四接口行为不变。 - [x] 密码不会出现在日志、页面响应、Gitea 工单或归档中。 - [x] 弹窗具备可见标签、密码自动填充语义、键盘焦点和可访问错误提示;拖选密码不会误关闭弹窗。 - [x] `go vet ./...`、`go test ./...` 及 Go 1.23.0 构建和无缓存测试通过。 ## 怎么验证 从 `admin/` 执行: ```powershell gofmt -w . go vet ./... go test ./... $env:GOTOOLCHAIN="go1.23.0" go build ./... go test ./... -count=1 Remove-Item Env:GOTOOLCHAIN ``` 浏览器验证: 1. 管理员打开弹窗,分别验证错误当前密码、长度边界、确认不一致。 2. 修改成功后确认跳回登录页,旧密码失败、新密码成功。 3. 在另一个已登录浏览器中确认旧 Session 同时失效。 4. 采购员登录后确认无入口,直接 POST 也被拒绝。 ## 风险和回退 - 风险:Session 撤销或 Cookie 清理遗漏会让旧会话继续可用;通过多 Session 集成测试覆盖。 - 风险:更新密码与撤销 Session 若不原子,会出现新密码已生效但旧 Session 未撤销;两步必须放在同一事务。 - 回退:回退本任务提交即可恢复原行为;无数据库迁移和数据结构回退。
Author
Owner

已开始实施。已将 #57 同步到父级 #14 与 MVP #15;当前工作区存在用户的 Client 与脚本改动,本任务只处理 Admin 认证相关文件并保持其他改动不动。

已开始实施。已将 #57 同步到父级 #14 与 MVP #15;当前工作区存在用户的 Client 与脚本改动,本任务只处理 Admin 认证相关文件并保持其他改动不动。
Author
Owner

实施完成,待用户验收

实现结果

  • 管理员顶部新增“修改密码”,采购员不显示入口。
  • 必须校验当前密码;目标账号只取当前 Session,表单不能指定其他用户。
  • 新密码沿用至少 6 个字符、最多 72 个字节及确认一致规则。
  • Repository 用旧密码哈希作并发条件,在同一事务更新密码并撤销该管理员全部 Web Session。
  • 失败时不回显密码,返回原页面、重开弹窗并聚焦对应错误字段。
  • 成功后清除认证 Cookie,跳转登录页;旧密码失效,新密码可登录。
  • 未增加数据库迁移,未改变 Client 四接口、采购员改密方式和真实下单开关。

自动化与浏览器验证

  • Service:错误当前密码不改数据/会话;长度、字节、确认和权限边界通过。
  • HTTP:管理员/采购员入口边界、CSRF 403、采购员 403、伪造 user_id 无效、多 Session 全撤销、Cookie 清除通过。
  • Chrome(1366×768、独立临时数据库):入口、焦点、拖选不误关、错误清空与聚焦、成功后新密码登录全部通过。
  • go vet ./... 通过。
  • go test ./... -count=1 全部通过。
  • Go 固定工具链输出 go version go1.23.0 windows/amd64;go build ./... 和无缓存测试通过。
  • 未验证:尚未在用户当前浏览器和实际 Admin 数据库中人工操作。

提交与归档

  • 实现提交:008bb876203ec5f3dc9b90c3fb7235ea891bdbd0
  • 归档提交:17b8f53113a3f961b73302062dd123601ff7c5f1
  • 归档:docs/task/57-管理员自助修改密码.md

工单保持打开,等待用户验收后再关闭并同步 #15、#14。

## 实施完成,待用户验收 ### 实现结果 - 管理员顶部新增“修改密码”,采购员不显示入口。 - 必须校验当前密码;目标账号只取当前 Session,表单不能指定其他用户。 - 新密码沿用至少 6 个字符、最多 72 个字节及确认一致规则。 - Repository 用旧密码哈希作并发条件,在同一事务更新密码并撤销该管理员全部 Web Session。 - 失败时不回显密码,返回原页面、重开弹窗并聚焦对应错误字段。 - 成功后清除认证 Cookie,跳转登录页;旧密码失效,新密码可登录。 - 未增加数据库迁移,未改变 Client 四接口、采购员改密方式和真实下单开关。 ### 自动化与浏览器验证 - Service:错误当前密码不改数据/会话;长度、字节、确认和权限边界通过。 - HTTP:管理员/采购员入口边界、CSRF 403、采购员 403、伪造 user_id 无效、多 Session 全撤销、Cookie 清除通过。 - Chrome(1366×768、独立临时数据库):入口、焦点、拖选不误关、错误清空与聚焦、成功后新密码登录全部通过。 - `go vet ./...` 通过。 - `go test ./... -count=1` 全部通过。 - Go 固定工具链输出 `go version go1.23.0 windows/amd64`;`go build ./...` 和无缓存测试通过。 - 未验证:尚未在用户当前浏览器和实际 Admin 数据库中人工操作。 ### 提交与归档 - 实现提交:`008bb876203ec5f3dc9b90c3fb7235ea891bdbd0` - 归档提交:`17b8f53113a3f961b73302062dd123601ff7c5f1` - 归档:`docs/task/57-管理员自助修改密码.md` 工单保持打开,等待用户验收后再关闭并同步 #15、#14。
Author
Owner

用户已于 2026-08-09 明确通过全部 Admin 待验收工单。本工单验收通过,现关闭,并同步父级 #15、#14 的任务清单。

用户已于 2026-08-09 明确通过全部 Admin 待验收工单。本工单验收通过,现关闭,并同步父级 #15、#14 的任务清单。
ila closed this issue 2026-08-09 21:16:28 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#57