将 inerit 和博客连接到同一个 Keycloak 时,很容易想当然地认为登录状态也会自然贯通。但共享认证服务器这一事实,与各服务自行建立登录状态,则是截然不同的两回事。
2026 年 11 月作业时,即使在一侧登录,另一侧也无法延续认证状态,仍需重新认证。此后,我们处理了双向登录关联、各服务权限、显式登出后即时重新登录的防止,以及现有账户迁移等问题。本文是当时作业记录中获得的设计教训,并非对当前运营状态的重新验证结果。
中央认证与服务会话是不同的
即使用户已在认证服务器上登录,新访问的服务可能尚未确认该结果。服务需要确认认证状态,经过必要的验证后,再建立自身的登录状态。这与直接读取其他服务的 Cookie 是不同的。
排查故障时,也应将问题分开看待。
- 认证服务器上是否存在有效的 SSO 会话?
- 新服务是否已启动认证确认流程?
- 响应验证和现有账户关联是否成功?
- 服务允许的用户和权限是否正确?
Keycloak 区分 SSO 用户会话和客户端会话,应用程序自身的会话也可能单独存在。如果将过期策略看作一团,就难以掌握在哪个边界出现了状态中断。Keycloak 会话过期设置
自动登录与强制登录是不同的
每次打开公开页面都将用户导向认证画面,与仅在已有认证的情况下延续登录状态,是两种不同的策略。
例如,Keycloak JavaScript 适配器的 login-required 和 check-sso 分别提供不同的进入体验。这只是用于说明差异的示例,并不意味着当时 inerit 使用了这些选项。OpenID Connect 的 prompt=none 也只是请求以无交互方式处理,并不会省略认证或同意。如有需要,会返回 login_required 等结果。若无条件重试,可能会在认证服务器和服务之间反复往返。Keycloak JavaScript 适配器,OpenID Connect 认证请求
基于 iframe 的静默认证确认还会受到浏览器第三方 Cookie 限制的影响。仅凭在某个浏览器中成功,并不能保证在所有环境中行为一致。
认证与使用许可是分离的
中央认证确认用户身份,但并不会自动决定是否允许其使用特定服务。即使某个账户在一个服务中已获批准,在其他服务中的使用条件也可能不同。在这种情况下,与其再次询问密码,不如区分待批准或访问受限状态并予以提示。
权限可以表现为 Keycloak 的客户端角色,也可以由服务自行管理。无论选择哪种方式,都必须在画面显示以及处理受保护请求的地方进行验证。协议中的用户同意与服务运营上的使用许可是不同的概念。Keycloak 客户端角色
登出包含用户的意图
即使清除了服务会话,中央 SSO 会话仍可能存在。此时如果页面立即重新启动自动登录,用户明明按下了登出按钮,却立刻看到已登录的画面。
首先必须决定是仅对当前服务进行登出,还是终止中央会话。如果采用服务单位登出,则还需决定自动登录抑制状态维持多久,以及在显式登录请求时如何解除。该状态是为了优化用户体验,不能替代服务器的认证与授权检查。
中央登出也不应假设其他服务的会话和画面会立即清理。OpenID Connect 分别定义了向认证服务器请求终止的 RP-Initiated Logout 和处理服务器间通知的 Back-Channel Logout。实际适用方式需根据服务需求和实现进行确认。
账户迁移与验证
在现有账户迁移中,不能仅看是否能登录。必须确认数据所有权和各服务批准状态是否正确关联到正确的账户,是否存在不明确或重复的账户。OpenID Connect 中处理标识符稳定性的基准是 iss 和 sub 的组合。但即使存在此标识符,也并不能自动证明其与现有本地账户的关联。OpenID Connect 标识符
验证时,追踪状态转换比一次登录成功更为重要。
- 无论从哪个服务开始,移动到另一个服务时是否按预期运行认证流程?
- 未认证用户是否在公开画面上陷入登录循环?
- 在已认证但未获使用许可的情况下,是否出现适当提示?
- 显式登出后,在刷新和重新访问时是否保持预期策略?
- 即使中央会话和服务会话的过期时间点不同,是否也能恢复?
- 现有账户的数据和权限是否正确维持?
SSO 的核心并不止于减少一次登录画面。必须决定由认证服务器证明的身份,以及各服务的会话、权限和用户的登出意图,分别在何处进行管理。




