diff --git a/MOCK.md b/MOCK.md index 88f3502..5d7d04d 100644 --- a/MOCK.md +++ b/MOCK.md @@ -59,7 +59,8 @@ npm run dev:mock | `GET /api/internal/admin/targets` | 同信封分页 | 一致 | | `PUT /api/internal/admin/targets/{id}` | body{baseUrl 非空, enabled 真布尔};成功 `data={targets:N}` | 一致 | | `GET /api/internal/admin/logs?pageIndex&pageSize&targetCode&callerAppKey` | pageSize 默认 50 上限 500;筛选**精确等值**、空串=不过滤;排序 id desc;`ts` ISO 字符串;backendCode 恒 null | 一致(先过滤再分页) | -| `POST /api/internal/routes/refresh` | 无入参 → `data={loaded,targets}` | 一致(返回内存实时条数:28/7) | +| `POST /api/internal/admin/routes/reload` | 无入参 → `data={loaded,targets}` | 一致(返回内存实时条数:28/7;`apps` 键 mock 无数据源,前端按 `-` 渲染) | +| `GET /api/internal/admin/session` | `data={ssoHost,principal}`,值来自已登录 CAS 会话 | `ssoHost` 返空串 → 顶栏「退出」不渲染(同 Notice 的 ssoHost 空态) | 前端请求带 `/open-gateway` 前缀(serviceHost),mock 中间件按剥前缀后的真实路径匹配。 diff --git a/src/api/apiDefinitions.ts b/src/api/apiDefinitions.ts index bbe937b..e17a9ef 100644 --- a/src/api/apiDefinitions.ts +++ b/src/api/apiDefinitions.ts @@ -15,6 +15,9 @@ export default { 'GatewayAdmin.createApp': ['POST', '/api/internal/admin/apps'], 'GatewayAdmin.updateApp': ['PUT', '/api/internal/admin/apps/{id}'], 'GatewayAdmin.logs': ['GET', '/api/internal/admin/logs'], - 'GatewayAdmin.refresh': ['POST', '/api/internal/routes/refresh'], + // 重载注册表:走浏览器面孪生入口。机器面 /api/internal/routes/refresh 只认内部令牌, + // 浏览器带 CAS 会话去打它会被 401 拦死(两口共用 RegistryReloader,返回体同形) + 'GatewayAdmin.reload': ['POST', '/api/internal/admin/routes/reload'], + 'GatewayAdmin.session': ['GET', '/api/internal/admin/session'], 'GatewayAdmin.proxyTest': ['POST', '/api/internal/admin/proxy-test'], }; diff --git a/src/assets/mock/gatewayApi.ts b/src/assets/mock/gatewayApi.ts index bb351b4..73d7fe3 100644 --- a/src/assets/mock/gatewayApi.ts +++ b/src/assets/mock/gatewayApi.ts @@ -498,10 +498,15 @@ export async function handleGatewayMockRequest(req: IncomingMessage, res: Server send(res, ok(listLogs(q))); return true; } - if (api === "/api/internal/routes/refresh" && method === "POST") { + if (api === "/api/internal/admin/routes/reload" && method === "POST") { send(res, ok({ loaded: routes.length, targets: targets.length })); return true; } + if (api === "/api/internal/admin/session" && method === "GET") { + // ssoHost 留空:mock 没有真 SSO,前端据此隐藏「退出登录」(同 Notice 的 ssoHost 空态行为) + send(res, ok({ ssoHost: "", principal: "mock 治理" })); + return true; + } if (api === "/api/internal/admin/proxy-test" && method === "POST") { const body = await readJsonBody(req); if (body === undefined) { diff --git a/src/components/layout.vue b/src/components/layout.vue index 59fb02e..7bfe07e 100644 --- a/src/components/layout.vue +++ b/src/components/layout.vue @@ -1,5 +1,5 @@ @@ -62,6 +82,8 @@ const reloadPage = inject("reload", () => {}) as () => void;
+ * 为什么不是 Notice 的 {@code ;redirectToReferer=
+ * 所以回跳目标不下服务端:整页跳去登录前把它记在 {@code sessionStorage}(同标签页、跨站点往返仍在), + * 回到控制台壳页时读出来换回原页签。副作用为零,且不引入任何服务端开放重定向面。 + */ + +const RETURN_KEY = "ysch-return-url"; + +/** 整页跳去 SSO 之前调用:记下当前控制台地址(含 hash 路由) */ +export function rememberReturnUrl(href: string = window.location.href): void { + try { + sessionStorage.setItem(RETURN_KEY, href); + } catch (e: any) { + // 隐私模式/配额满:最坏只是回到默认页,不影响登录本身 + } +} + +/** + * 取出并清掉回跳目标,返回 vue-router 的 hash 路由段(如 {@code /ledger?pageIndex=2})。 + * 只认「同 origin + 同一壳页」的地址,其余一律丢弃——防把用户导向站外或别的应用。 + */ +export function consumeSsoReturnUrl(): string | null { + let raw: string | null = null; + try { + raw = sessionStorage.getItem(RETURN_KEY); + if (raw) sessionStorage.removeItem(RETURN_KEY); + } catch (e: any) { + return null; + } + if (!raw) return null; + try { + const u = new URL(raw); + if (u.origin !== window.location.origin) return null; + if (u.pathname !== window.location.pathname) return null; + const route = u.hash.replace(/^#\/?/, "/"); + return route && route !== "/" ? route : null; + } catch (e: any) { + return null; + } +}