Archived
4.1 KiB
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 配置,前端不用动。