fix: 每日进销存截图改用系统库专用服务账号身份 #42

Merged
youruo merged 1 commits from codex/daily-inventory-notify-identity-0927 into main 2026-09-27 09:29:07 +08:00
Collaborator

问题

PR #33 的定时截图通知上线后,端到端验证发现截图永远失败:等待页面数据行 3 分钟超时。
排查结论是截图身份不被前端认可,而不是页面或接口本身有问题(接口返回 26 个仓库,
真实浏览器打开页面 5.6 秒完成渲染,无 console 错误)。

  • /api/auth/verify 会执行 getResolvedUserWithPageAccess(decoded.sub),
    要求令牌的 sub 是系统库 users 表中真实且 active 的用户;
  • 原实现签发的是 sub='daily-inventory-screenshot-bot' 的合成身份,用户表里没有这一行;
  • verify 返回 401 {"valid":false},前端清除令牌并跳转 /login,截图因此拿不到任何数据。

处理

在系统库维护一个仅供服务端使用的专用账号(auth_source=service),令牌 sub 使用其 id:

  • 账号不存在时按 role=admin、status=active、auth_source=service 创建;
  • 密码哈希是随机值且无人知晓,账号无法通过密码登录;
  • 已存在时复用 id;仅对 auth_source=service 的本服务账号补齐管理员与启用状态,不触碰人工账号;
  • 令牌仍为 15 分钟过期、只注入浏览器 localStorage,不出现在地址、日志或响应里;
  • 账号 id 进程内缓存;删除该行即可彻底回收权限。

用户名可用环境变量 DAILY_INVENTORY_SCREENSHOT_USERNAME 覆盖,默认 daily_inventory_screenshot_bot。

影响范围

  • backend/src/services/dailyInventoryScreenshot.js:新增服务账号维护与令牌签发改造;
  • backend/test/dailyInventoryNotification.test.js:新增 2 项测试(账号创建/复用、令牌 sub 校验)。

未改动鉴权中间件与 /api/auth/verify 语义,未改动数据库表结构,新增数据仅 1 行服务账号。

验证

  • node --test test/dailyInventoryNotification.test.js:19/19 通过;
  • npm --prefix backend run check:366/367 通过,唯一失败为既有的 resilientSecretStore
    Windows 文件权限用例,与本改动无关;
  • 语法检查 171 个文件通过。

部署后仍需验证:在页面点击「立即测试」确认截图上传成功并返回可访问的 HTTPS 地址。

## 问题 PR #33 的定时截图通知上线后,端到端验证发现截图永远失败:等待页面数据行 3 分钟超时。 排查结论是截图身份不被前端认可,而不是页面或接口本身有问题(接口返回 26 个仓库, 真实浏览器打开页面 5.6 秒完成渲染,无 console 错误)。 - `/api/auth/verify` 会执行 `getResolvedUserWithPageAccess(decoded.sub)`, 要求令牌的 `sub` 是系统库 `users` 表中真实且 `active` 的用户; - 原实现签发的是 `sub='daily-inventory-screenshot-bot'` 的合成身份,用户表里没有这一行; - verify 返回 `401 {"valid":false}`,前端清除令牌并跳转 `/login`,截图因此拿不到任何数据。 ## 处理 在系统库维护一个仅供服务端使用的专用账号(`auth_source=service`),令牌 `sub` 使用其 id: - 账号不存在时按 `role=admin`、`status=active`、`auth_source=service` 创建; - 密码哈希是随机值且无人知晓,账号无法通过密码登录; - 已存在时复用 id;仅对 `auth_source=service` 的本服务账号补齐管理员与启用状态,不触碰人工账号; - 令牌仍为 15 分钟过期、只注入浏览器 localStorage,不出现在地址、日志或响应里; - 账号 id 进程内缓存;删除该行即可彻底回收权限。 用户名可用环境变量 `DAILY_INVENTORY_SCREENSHOT_USERNAME` 覆盖,默认 `daily_inventory_screenshot_bot`。 ## 影响范围 - `backend/src/services/dailyInventoryScreenshot.js`:新增服务账号维护与令牌签发改造; - `backend/test/dailyInventoryNotification.test.js`:新增 2 项测试(账号创建/复用、令牌 sub 校验)。 未改动鉴权中间件与 `/api/auth/verify` 语义,未改动数据库表结构,新增数据仅 1 行服务账号。 ## 验证 - `node --test test/dailyInventoryNotification.test.js`:19/19 通过; - `npm --prefix backend run check`:366/367 通过,唯一失败为既有的 `resilientSecretStore` Windows 文件权限用例,与本改动无关; - 语法检查 171 个文件通过。 部署后仍需验证:在页面点击「立即测试」确认截图上传成功并返回可访问的 HTTPS 地址。
youruo added 1 commit 2026-09-27 09:25:49 +08:00
页面启动会调用 /api/auth/verify,该接口要求令牌 sub 必须是系统库 users 表中真实且 active
的用户。原实现签发的是一个不存在于用户表的合成身份,verify 返回 401,前端清除令牌并跳转
登录页,截图因此永远拿不到数据(等待数据行 3 分钟超时)。

改为在系统库维护一个仅供服务端使用的专用账号:
  · 账号不存在时按 role=admin、status=active、auth_source=service 创建
  · 密码哈希为随机值且无人知晓,账号无法通过密码登录
  · 已存在时复用 id,并仅对 auth_source=service 的本服务账号补齐管理员与启用状态
  · 令牌 sub 使用该账号 id,15 分钟过期,仍只注入 localStorage
  · 账号 id 进程内缓存,删除该行即可回收权限

新增 2 项单元测试:账号创建/复用与令牌 sub 校验。
youruo merged commit 485097354b into main 2026-09-27 09:29:07 +08:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lunanting/cangku#42
No description provided.