修复 QuantUX JWT 过期导致 MCP 降级为 guest #1

Open
opened 2026-08-25 15:17:40 +08:00 by ila · 3 comments
Owner

原始问题

2026-08-25,Codex 通过远程 QuantUX MCP 可以正常完成 MCP API Key 认证和健康检查,但 quantux_list_apps 返回空列表,quantux_create_app 返回 HTTP 405。用户确认本机 quantux.env 未修改,且浏览器可以正常访问 https://qux.ilapage.cn/。

已确认根因

认证分为两层:

  1. Codex → MCP:使用本机 quantux.env 的 Bearer API Key,当前正常。
  2. MCP → QuantUX:容器启动时使用管理员账号登录,将 QuantUX JWT 长期缓存在进程内。

线上 MCP 容器于 2026-08-17 启动并成功登录,JWT 于 2026-08-24 到期。代码仅在进程启动时调用 _auto_login(),不会刷新过期 JWT。QuantUX 后端解析失败后把请求视为 guest:列表返回空,创建 App 返回误导性的 405。现有健康检查只判断 Token 字符串是否存在,因此错误显示 logged_in=true。

另外,当前导出 URL 把 MCP API Key 放在 query 参数中,访问日志会保留完整 URL,存在凭据泄露风险。

目标

  • QuantUX JWT 即将到期或已过期时自动重新登录。
  • 多个并发 MCP 请求只触发一次刷新。
  • 认证失败时允许自动重登并安全重试一次,不无限重试。
  • 健康检查真实报告 Token 是否有效及过期时间。
  • 导出文件不再要求把长期 MCP API Key 写入 URL。
  • 不在代码、测试、日志和工单中记录任何真实密码、JWT 或 API Key。

实施方案

  1. 为 QuantUX Client 增加 JWT 到期解析,只读取 exp,不把 Token 写日志。
  2. 在服务端建立线程安全的认证会话管理器:
    • 无 Token、已过期或进入安全提前量时使用已配置管理员凭据重新登录;
    • 同一时刻只有一个请求登录;
    • 工具调用前确保会话有效。
  3. 对可明确识别的认证失败自动刷新并重试一次;不对一般 4xx、业务 405 或写入错误盲目重放。
  4. 健康检查返回 MCP、QuantUX 可达性、logged_in、token_valid、token_expires_at,且不会把仅存在的过期 Token 视为有效。
  5. 导出下载改用随机、可撤销的短期下载令牌,或等效的不暴露长期 MCP API Key 的方式;旧长期 Key 不出现在新生成 URL 和访问日志。
  6. 部署后人工轮换 MCP API Key,并同步更新客户端安全配置。轮换和线上重启属于高风险步骤,代码完成后再次确认。

非目标

  • 不修改 QuantUX 用户密码或业务数据。
  • 不升级 QuantUX 前后端镜像。
  • 不改变原型模型、控件或导出内容。
  • 不在未确认前重启线上容器或轮换凭据。

验收标准

  • 使用已过期 JWT 调用列表/创建前只自动登录一次并正常继续。
  • 并发请求只产生一次登录。
  • 缺少管理员凭据时给出明确认证错误,不返回假 logged_in=true。
  • 一般 405 不被错误当成认证问题重复写入。
  • 健康检查能区分无 Token、有效、临近过期、已过期。
  • 新导出链接和访问日志不包含长期 MCP API Key。
  • 单元测试与 MCP 回归测试通过。
  • 代码提交、推送并回写验证证据。
  • 用户确认后才部署重启和轮换 API Key。

风险与回退

自动重试写操作必须严格限制为“请求尚未以有效身份执行”的认证失败场景,防止重复创建或重复更新。部署异常时回退旧镜像并重启旧容器;凭据轮换后不能回退到旧客户端配置。

文档影响

更新 README 的认证生命周期、健康检查字段、导出下载认证与部署轮换步骤。

## 原始问题 2026-08-25,Codex 通过远程 QuantUX MCP 可以正常完成 MCP API Key 认证和健康检查,但 `quantux_list_apps` 返回空列表,`quantux_create_app` 返回 HTTP 405。用户确认本机 `quantux.env` 未修改,且浏览器可以正常访问 `https://qux.ilapage.cn/`。 ## 已确认根因 认证分为两层: 1. Codex → MCP:使用本机 `quantux.env` 的 Bearer API Key,当前正常。 2. MCP → QuantUX:容器启动时使用管理员账号登录,将 QuantUX JWT 长期缓存在进程内。 线上 MCP 容器于 2026-08-17 启动并成功登录,JWT 于 2026-08-24 到期。代码仅在进程启动时调用 `_auto_login()`,不会刷新过期 JWT。QuantUX 后端解析失败后把请求视为 guest:列表返回空,创建 App 返回误导性的 405。现有健康检查只判断 Token 字符串是否存在,因此错误显示 `logged_in=true`。 另外,当前导出 URL 把 MCP API Key 放在 query 参数中,访问日志会保留完整 URL,存在凭据泄露风险。 ## 目标 - QuantUX JWT 即将到期或已过期时自动重新登录。 - 多个并发 MCP 请求只触发一次刷新。 - 认证失败时允许自动重登并安全重试一次,不无限重试。 - 健康检查真实报告 Token 是否有效及过期时间。 - 导出文件不再要求把长期 MCP API Key 写入 URL。 - 不在代码、测试、日志和工单中记录任何真实密码、JWT 或 API Key。 ## 实施方案 1. 为 QuantUX Client 增加 JWT 到期解析,只读取 `exp`,不把 Token 写日志。 2. 在服务端建立线程安全的认证会话管理器: - 无 Token、已过期或进入安全提前量时使用已配置管理员凭据重新登录; - 同一时刻只有一个请求登录; - 工具调用前确保会话有效。 3. 对可明确识别的认证失败自动刷新并重试一次;不对一般 4xx、业务 405 或写入错误盲目重放。 4. 健康检查返回 MCP、QuantUX 可达性、`logged_in`、`token_valid`、`token_expires_at`,且不会把仅存在的过期 Token 视为有效。 5. 导出下载改用随机、可撤销的短期下载令牌,或等效的不暴露长期 MCP API Key 的方式;旧长期 Key 不出现在新生成 URL 和访问日志。 6. 部署后人工轮换 MCP API Key,并同步更新客户端安全配置。轮换和线上重启属于高风险步骤,代码完成后再次确认。 ## 非目标 - 不修改 QuantUX 用户密码或业务数据。 - 不升级 QuantUX 前后端镜像。 - 不改变原型模型、控件或导出内容。 - 不在未确认前重启线上容器或轮换凭据。 ## 验收标准 - [ ] 使用已过期 JWT 调用列表/创建前只自动登录一次并正常继续。 - [ ] 并发请求只产生一次登录。 - [ ] 缺少管理员凭据时给出明确认证错误,不返回假 `logged_in=true`。 - [ ] 一般 405 不被错误当成认证问题重复写入。 - [ ] 健康检查能区分无 Token、有效、临近过期、已过期。 - [ ] 新导出链接和访问日志不包含长期 MCP API Key。 - [ ] 单元测试与 MCP 回归测试通过。 - [ ] 代码提交、推送并回写验证证据。 - [ ] 用户确认后才部署重启和轮换 API Key。 ## 风险与回退 自动重试写操作必须严格限制为“请求尚未以有效身份执行”的认证失败场景,防止重复创建或重复更新。部署异常时回退旧镜像并重启旧容器;凭据轮换后不能回退到旧客户端配置。 ## 文档影响 更新 README 的认证生命周期、健康检查字段、导出下载认证与部署轮换步骤。
Author
Owner

实施完成:等待线上部署与凭据轮换确认

已实现

  • 新增 QuantUX JWT exp 检查;调用工具前在 5 分钟安全提前量内自动重新登录。
  • 使用进程内互斥锁,过期并发请求只触发一次登录。
  • QuantUX 明确返回 401/403 时自动刷新并重试一次;一般 405 不重试,避免重复写入。
  • 健康检查现在返回真实的 logged_in、token_valid、token_expires_at 和 token_refresh_due。
  • 导出下载不再把长期 MCP API Key 放入 URL,改为单文件范围、默认 10 分钟有效的随机下载令牌。
  • Dockerfile、Compose 和 README 已同步更新。
  • 未记录或提交任何真实账号密码、JWT 或 API Key。

验证

  • python -m py_compile quantux_client.py quantux_auth.py quantux_export.py quantux_verify.py server.py:通过。
  • python -m unittest discover -s tests -p 'test_*.py' -v:7 项通过。
  • 覆盖:过期刷新、12 路并发只登录一次、缺少凭据、401 单次重试、405 不重试、健康状态、下载令牌文件范围和过期。
  • git diff --check:通过。
  • 本机没有 Docker CLI,因此未在本机执行镜像构建;将于获得线上部署确认后先在服务器构建,再切换容器和验证。

提交

  • 16500d867d76d704bb95524fcbea310da4eb2d14
  • 已推送 OPC/quantux_mcp main。

尚未执行的高风险步骤

  • 尚未重建或重启线上 quantux-mcp 容器。
  • 尚未轮换 MCP API Key。
  • 尚未修改本机 C:\Users\ila20\.codex\quantux.env。

获得用户确认后,将按“备份当前配置 → 服务器拉取/构建 → 重启单个 MCP 容器 → 健康/创建/导出验证 → 轮换 API Key并同步客户端 → 再验证”的顺序执行。

## 实施完成:等待线上部署与凭据轮换确认 ### 已实现 - 新增 QuantUX JWT `exp` 检查;调用工具前在 5 分钟安全提前量内自动重新登录。 - 使用进程内互斥锁,过期并发请求只触发一次登录。 - QuantUX 明确返回 401/403 时自动刷新并重试一次;一般 405 不重试,避免重复写入。 - 健康检查现在返回真实的 `logged_in`、`token_valid`、`token_expires_at` 和 `token_refresh_due`。 - 导出下载不再把长期 MCP API Key 放入 URL,改为单文件范围、默认 10 分钟有效的随机下载令牌。 - Dockerfile、Compose 和 README 已同步更新。 - 未记录或提交任何真实账号密码、JWT 或 API Key。 ### 验证 - `python -m py_compile quantux_client.py quantux_auth.py quantux_export.py quantux_verify.py server.py`:通过。 - `python -m unittest discover -s tests -p 'test_*.py' -v`:7 项通过。 - 覆盖:过期刷新、12 路并发只登录一次、缺少凭据、401 单次重试、405 不重试、健康状态、下载令牌文件范围和过期。 - `git diff --check`:通过。 - 本机没有 Docker CLI,因此未在本机执行镜像构建;将于获得线上部署确认后先在服务器构建,再切换容器和验证。 ### 提交 - `16500d867d76d704bb95524fcbea310da4eb2d14` - 已推送 `OPC/quantux_mcp main`。 ### 尚未执行的高风险步骤 - 尚未重建或重启线上 `quantux-mcp` 容器。 - 尚未轮换 MCP API Key。 - 尚未修改本机 `C:\Users\ila20\.codex\quantux.env`。 获得用户确认后,将按“备份当前配置 → 服务器拉取/构建 → 重启单个 MCP 容器 → 健康/创建/导出验证 → 轮换 API Key并同步客户端 → 再验证”的顺序执行。
Author
Owner

已部署,等待验收

  • 修复提交:16500d867d76d704bb95524fcbea310da4eb2d14
  • 部署目录:/home/ubuntu/quantux-mcp
  • 部署前备份:/home/ubuntu/quantux-mcp/backups/issue-1-20260825-152400
  • 新镜像:sha256:eae3c401f062d39f8cb453051e5d9a5c4ac7ac31a2fb13178e0b6084444cdd60
  • 容器内单元测试:7 项全部通过。
  • 线上健康检查:登录有效,JWT 有效期可见,已有 11 个应用恢复可见。
  • 实际 MCP 冒烟:创建应用、增加页面/组件、导出、短期下载链接、验证、删除临时应用均通过;导出链接未携带长期 API Key。
  • API Key 已轮换:新 Key 可通过网关认证,旧 Key 返回 401;本机 C:\Users\ila20\.codex\quantux.env 已同步更新。未在工单、日志或源码记录密钥内容。
  • 服务日志:自动登录成功,无 warning/error。

注意:当前已经运行的 Codex mcp-remote 进程仍缓存旧 Key。需要重启 Codex 或重新连接 QuantUX MCP 后,当前会话才会读取新配置;服务端本身已验证正常。

状态保持待用户验收,不关闭工单。

## 已部署,等待验收 - 修复提交:`16500d867d76d704bb95524fcbea310da4eb2d14` - 部署目录:`/home/ubuntu/quantux-mcp` - 部署前备份:`/home/ubuntu/quantux-mcp/backups/issue-1-20260825-152400` - 新镜像:`sha256:eae3c401f062d39f8cb453051e5d9a5c4ac7ac31a2fb13178e0b6084444cdd60` - 容器内单元测试:7 项全部通过。 - 线上健康检查:登录有效,JWT 有效期可见,已有 11 个应用恢复可见。 - 实际 MCP 冒烟:创建应用、增加页面/组件、导出、短期下载链接、验证、删除临时应用均通过;导出链接未携带长期 API Key。 - API Key 已轮换:新 Key 可通过网关认证,旧 Key 返回 401;本机 `C:\Users\ila20\.codex\quantux.env` 已同步更新。未在工单、日志或源码记录密钥内容。 - 服务日志:自动登录成功,无 warning/error。 注意:当前已经运行的 Codex `mcp-remote` 进程仍缓存旧 Key。需要重启 Codex 或重新连接 QuantUX MCP 后,当前会话才会读取新配置;服务端本身已验证正常。 状态保持待用户验收,不关闭工单。
Author
Owner

Codex 重启后验证

  • 用户已重启 Codex,mcp-remote 已重新读取本机配置。
  • quantux_health:MCP 与 QuantUX 后端均为 ok,logged_in=true、token_valid=true、token_refresh_due=false。
  • quantux_list_apps:成功返回当前账号的 11 个已有原型。

结论:客户端旧 Key 缓存已消除,修复后的 QuantUX MCP 可正常使用。工单继续保持待用户验收。

## Codex 重启后验证 - 用户已重启 Codex,`mcp-remote` 已重新读取本机配置。 - `quantux_health`:MCP 与 QuantUX 后端均为 `ok`,`logged_in=true`、`token_valid=true`、`token_refresh_due=false`。 - `quantux_list_apps`:成功返回当前账号的 11 个已有原型。 结论:客户端旧 Key 缓存已消除,修复后的 QuantUX MCP 可正常使用。工单继续保持待用户验收。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/quantux_mcp#1