This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/docs/统一鉴权接入记录-2026-08-26.md
T

4.1 KiB

统一鉴权中心(Keycloak)接入记录 —— 2026-08-26

依据 BPOS-MVP/docs/ 三份文档(keycloak-frontend-guide / API文档-鉴权与人员 / 前端对接说明-统一鉴权中心,ADR-012)完成前端侧改造。后端以测试服 150.158.83.131:46100 实测:/api/me 无头 401「缺少 Bearer token」、/api/login 410 退役,Keycloak corp realm 在线。

机制

  • 本端 = 用户端 web-portal(public client,无 secret,PKCE S256);要求 realm 角色 user。
  • token 只在 keycloak-js 内存里,刷新页面靠 SSO 会话静默恢复;每个请求经 freshToken() 挂 Authorization: Bearer。
  • 准入只看 GET /api/me 的 ends(角色 → 端):入口亮灯、深链保护、个人中心展示都读它;ends: [] 摆「未授权」页而不是登录页。
  • 401 先强刷一次 token 重试,仍 401 落登录页;403 不重试(端不够,重登没用)。
  • SSE 与「下载原件」走 60 秒票据(GET /api/auth/ticket → ?ticket=);SSE 断线后重新取票据重建(浏览器自动重连的旧 URL 必 401)。

改动清单

文件 改动
packages/contracts/src/org.ts 加 SURFACES/surfaceSchema/principalSchema;sessionSchema 标 @deprecated(本仓库 apps/api 仍是旧后端,契约暂留)
packages/contracts/src/api/workbench.ts 加 meRoute(GET /api/me)、authTicketRoute(GET /api/auth/ticket);session/login/logout 三条标 @deprecated
apps/web/package.json + keycloak-js@26.2.4
apps/web/.env.development / .env.production(新) VITE_KEYCLOAK_URL/REALM/CLIENT_ID=web-portal/VITE_REQUIRED_ROLE=user
apps/web/public/silent-check-sso.html(新) 静默 SSO 探测落点页
apps/web/src/shared/auth.ts(新) keycloak 实例 + initAuth/login/logout/freshToken/forceRefreshToken;未初始化(测试)时 freshToken 回 undefined 不带头
apps/web/src/shared/typed-fetch.ts 去 cookie,挂 Bearer;401 → forceRefreshToken 后重试一次
apps/web/src/app/main.tsx 模块加载即 initAuth();Gate 三分支(未登录→登录页 / 角色不够→Denied+登出 / 正常→/api/me)+ ends 深链保护(落到能进的第一个端)
apps/web/src/features/auth/…/LoginPage.tsx 删账号口令表单,改「前往统一登录」跳 Keycloak
apps/web/src/shared/gov/surfaces.ts canSeeSurface(me, surface) = me.ends.includes(surface);删 SURFACE_FNS
apps/web/src/app/app-shell.tsx / gov-shell.tsx / desk-me/…/MePage.tsx session→me(queryKeys.me);登出 = 清缓存 + keycloak.logout();MePage「我的权限」改「我的准入」(角色 + 可进的端,端可直接点过去)
apps/web/src/app/subscribe.ts SSE 走票据,error 时关旧连接、重取票据、1s 后重建
apps/web/src/features/desk-task/…/FileViewer.tsx 「下载原件」点击时现取票据拼 ?ticket= 再跳转
apps/web/src/shared/query-keys.ts session → me
vitest.config.ts 补 @web-shared / @features 别名(与 web 的 vite.config 同口径)
apps/web/src/shared/__tests__/typed-fetch.test.ts 断言前加 flushToken()(fetch 前多了一道取 token 的微任务)
apps/web/src/shared/gov/__tests__/surfaces.test.ts canSeeSurface 改测 ends 口径

验证

  • tsc --noEmit(web + node)、eslint 全部改动文件、vitest run 全仓 1691 过。
  • 浏览器实测:localhost:5173 → 登录页(前往统一登录)→ 跳 keycloak.akhr-ai.com/realms/corp/...auth?client_id=web-portal&…&code_challenge_method=S256,登录页正常渲染(无 redirect_uri 报错)。
  • 真人账号登录 → /api/me → 各端落点这后半段需要有权限的账号走一遍(判据见对接说明 §9)。

已知遗留

  • 运营中心「员工」页还在调四条已退役接口(建人/停用/停用前置/岗位授权,410),需按对接说明 §7 换成同步名册 / 指派岗位 / 在途工作 / 角色→端 —— 未做,等指令。
  • grantSchema / Session 等旧类型契约里标了 @deprecated,前端已不 import(LoginPage/main/shells/surfaces 全换完),契约物理删除留待后端侧一起收。
  • Keycloak 侧若要收回 localhost 回调(上线清单 §14),找管理员改 client 配置,前端不用动。