启动自检 issuer 不一致拒绝启动;路由覆盖 fail-closed;Keycloak 配置解析测试(ADR-012)

上一个任务把统一鉴权中心接上了,但缺配置照常起、issuer 配错也照常起 ——
每个请求都 401 还查不出原因。boot() 开头补两道保险:缺
KEYCLOAK_URL/REALM/CLIENT_ID 直接拒绝启动;配了就拉一次
.well-known/openid-configuration 核对 issuer,不一致同样拒绝启动
(话里带期望/实际/KC_HOSTNAME,照后端接入手册第 5 步)。

另加路由覆盖 it 测试:Hono 里每条注册路由都必须能在 appRouteRegistry()
里查到归属,查不到就是一个没人管的权限口子。真库跑通,96 条路由全部
有归属、0 条查不到——把上一个任务里人工核对的结论固化成测试。
This commit is contained in:
xcs
2026-08-25 18:04:21 +08:00
parent 8dc71db9d8
commit 61622f94d5
5 changed files with 185 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
/**
* 启动自检(手册第 5 步;ADR-012):拉 `.well-known/openid-configuration`,
* issuer 与本地拼出来的不一致就别起 —— 配错了每个请求都 401 还查不出原因,不如启动时就说清楚。
*/
import type { KeycloakConfig } from './config.ts';
export async function checkKeycloakConnection(
kc: KeycloakConfig,
fetchImpl: typeof fetch = fetch,
): Promise<{ issuer: string; clientId: string }> {
const url = `${kc.issuer}/.well-known/openid-configuration`;
const resp = await fetchImpl(url, { signal: AbortSignal.timeout(5000) });
if (!resp.ok) throw new Error(`拉取发现文档失败 (${resp.status}): ${url}`);
const conf = (await resp.json()) as { issuer?: unknown };
if (conf.issuer !== kc.issuer) {
throw new Error(
`issuer 不一致!\n 期望: ${kc.issuer}\n 实际: ${String(conf.issuer)}\n` +
' → Keycloak 的 KC_HOSTNAME 配错了,或本服务的 KEYCLOAK_URL 写错了',
);
}
return { issuer: kc.issuer, clientId: kc.clientId };
}