Archived
46 lines
4.1 KiB
Markdown
46 lines
4.1 KiB
Markdown
# 统一鉴权中心(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 配置,前端不用动。
|