百积木文档
开发指南平台应用、模块与 Bundle 开发平台应用开发

安全与故障排查

保护 Bundle 平台应用 token,并按授权链路定位入口、回跳和权限问题。

安全要求

  • 使用 PKCE S256,每次授权生成新的 verifier 和 state。
  • redirectUri 必须与登记的应用入口同源。
  • 不在 URL、日志、错误上报、埋点或截图中记录 token。
  • token 仅保存在 SDK client 内存中,校验 workspaceId + runtimeAppId + installId 和过期时间;不要自行持久化。
  • 内存保存 token 不消除 XSS 风险;必须执行内容安全策略和依赖安全检查。
  • 应用停用、卸载、权限变化或用户退出时,清理本地会话。
  • 后端服务只信任平台网关注入并验证过的上下文,不信任前端自行传入的 userId 或 workspaceId。

旧外部入口被拒绝

若启动提示“旧签名启动应用必须创建环境托管应用新版本”,或授权提示“外部托管应用必须使用自己的后台授权”, 先检查安装锁定的平台应用版本是否仍为 TRUSTED_EXTERNAL_APP。定义或版本创建成功不等于当前启动链路支持它。 按 迁移历史外部应用 更新源码、入口、SDK 和完整 Bundle 版本链;不要改成普通外链后继续申请平台 token。

环境配置读取或版本路径校验失败

如果 platform-app workspace list 只返回 /index.html,使用 platform-app workspace launch-context <resourceLocator> --workspace-id <workspaceId> --json 取得该安装的完整 accessUrl。如需检查准确版本部署或跨工作区分享,分别使用 platform-app version address 和 platform-app entry,见 三类入口查询。

检查实际入口同源的 /.well-known/baijimu-platform-application.json 是否可通过 HTTPS 直接读取, 并确认应用身份和精确 origin 与当前版本一致,SDK 10.2.0 的配置合同为 2.0.0。构建归档不能覆盖配置路径,不能把 API 或授权地址从 URL 参数补入。 出现 404、NoSuchKey 或返回 HTML 时,先区分入口类型:

  • 历史 STATIC_SPA 或 TRUSTED_EXTERNAL_APP:按完整迁移流程创建 ENVIRONMENT_HOSTED_APP 新版本并升级 Bundle。无需为旧站点追加配置,也无需自行执行站点部署。
  • 已安装的 ENVIRONMENT_HOSTED_APP:从当前安装返回的 accessUrl 访问,核对版本是否已升级、资源台账是否已验证、托管物化是否完成,再排查平台生成配置的步骤。

不要把旧站点的 404 直接解释为 CLI 缺少“配置托管入口”的命令;也不要增加硬编码网关、授权地址、公共 SaaS 默认地址或旧配置缓存。

授权页提示缺少参数

检查参数是否写在 Hash Router 路由后:

正确:https://console.baijimu.com/#/platform-app-authorize?installId=...
错误:https://console.baijimu.com/?installId=...#/platform-app-authorize

分享入口提示需要安装 Bundle

这是预期的授权边界,不是平台应用缺少单独授权。确认分享地址使用 /bundle-app/{bundleId}/{platformAppId},选择正确工作区,并让工作区所有者或管理员安装提示的 Bundle。平台应用不能脱离 Bundle 单独安装。

redirectUri 不合法

检查协议、域名和端口是否与环境托管后的实际入口同源,并核对同源配置的 applicationOrigin;SDK 10.2.0 新部署不含 releasePath。清单中的 /index.html 是构建产物内路径,不能直接充当授权回跳 URL,也不能用外部域名替换托管入口。

缺少 PKCE verifier

通常是授权前没有保存 verifier、回跳进入了不同浏览器会话,或者应用刷新逻辑提前清理了 sessionStorage。重新开始授权并保证同一浏览器会话完成回跳。

state 校验失败

停止兑换 token。检查是否同时发起了多个授权请求、多个安装共用了同一个 storage key,或者回跳参数被路由层覆盖。

授权回跳后提示缺少 installId

先查看平台安装记录返回的 accessUrl,确认平台已在托管入口中追加 installId。如果首次跳转有该参数、授权回跳后却 消失,通常是应用自行执行了类似 history.replaceState({}, "", location.pathname + location.hash) 的清理逻辑, 把整个查询串连同 installId 一起删除了。

不要为此增加缓存态 installId 或从其他字段猜测安装身份。环境托管应用必须让 @baijimu/platform-application-sdk 完成回跳清理;SDK 只删除一次性的 code 和 state,保留入口身份参数。 迁移旧项目时,应同时删除自实现的 PKCE、token 缓存和 Gateway client,避免两套状态机竞争。

token 兑换失败

依次确认:

  1. code 尚未使用且没有过期。
  2. installId 与发起授权时一致。
  3. codeVerifier 与原始 challenge 匹配。
  4. 请求体字段使用 code 和 codeVerifier。

平台切换账号后应用仍是旧用户

先核对部署产物使用的 SDK 版本。SDK 6.0.0 以前会复用应用 origin 的持久化会话,平台与应用域名的 存储不会因另一边退出自动同步。升级 SDK、删除应用自实现缓存并重新构建、创建应用版本、升级 Bundle,再重新打开应用验证。 不要把 token 的有效期当成当前平台身份的证明,也不要通过修改 userId 参数补偿错误身份。

SDK 6.0.0 新开或刷新重新授权;已打开页面的即时账号同步需要平台会话联动。排查时分别记录平台身份、 应用授权返回身份、应用版本和打开时间,不记录完整 token。

接口返回无权限

不要立即重新登录。先区分:

  • App Gateway 明确拒绝会话,SDK 已清空 getSession():重新授权。
  • 后端返回合法 CModel UNAUTHORIZED:保留登录会话并展示业务错误;HTTP 401 本身不能替代 SDK 的会话判断。
  • 模块方法未声明:创建包含正确最小权限的平台应用新版本。
  • 运行目标缺失或引用未绑定:按目标 Owner 的当前事实修正资源配置;它不构成 Bundle 安装门禁。
  • 用户没有目标业务权限:由业务权限管理员处理。
  • 后端服务异常:查看目标服务日志和追踪信息。
  • 模块不存在或试图访问外包 Module:核对应用所属 Bundle 与 RCS 的当前模块事实;新调用不使用 targets 映射。跨包服务经本包 Module 属性绑定,来源凭据和用户权限错误分别按 Owner 的真实结果处理。

排障时保留 installId、runtimeAppId、平台应用版本号、模块 service、方法名和平台 返回的公开错误信息;不要保存完整 token。

本页内容