
文章目录前言一、先把四种凭证分清楚二、一次完整的 SSO 登录发生了什么三、state 到底解决了什么问题四、Ticket 必须由后端验证五、SSO 身份如何变成平台用户六、如何把用户放进 Spring Security七、后续请求怎样获取当前用户八、使用 Session,为什么还要保留 CSRF最后前言很多系统接入SSO时,都会走这样一条路:SSO 登录成功 - 获取用户信息 - 业务系统再生成一个 JWT - 前端保存到 localStorage - 每次请求携带 X-Access-Token这套方案能用,但它很容易制造出两套认证体系:集团 SSO 有自己的登录状态,业务系统又维护一套 JWT。账号禁用、Token 过期、主动退出和权限变化,都要在两套体系之间保持一致。只要其中一个环节没有处理好,就会出现这些问题:集团 SSO 已经退出,门户 JWT 仍然有效;平台账号已经禁用,旧 JWT 还能继续访问;Redis、JWT、userIdHeader 同时保存用户信息,却没人能说清哪个才可信;前端长期把 Token 放在localStorage,一旦发生 XSS,Token 可能被直接读取。因此,在当前项目中,我们没有在 SSO 登录成功后再生成门户 JWT,而是选择了:集团 SSO 负责证明“你是谁”,Spring Security 负责维护“你在本系统中的登录状态”,平台账号和角色负责决定“你能做什么”。登录成功后,后端创建 Spring SecuritySecurityContext,再通过 Spring Session 保存到 Redis。浏览器只持有 HttpOnly 的SESSIONCookie。这篇文章结合当前项目的真实实现,讲清楚这条链路是怎么完成的,以及这套方案为什么值得复用。一、先把四种凭证分清楚这套认证流程中,会出现四种容易被统称为“Token”的数据,但它们的职责完全不同。凭证作用保存位置生命周期SSO Ticket集团 SSO 证明当前用户身份回调 URL验证一次后立即丢弃SSO state绑定发起登录的浏览器与本次回调临时 Cookie + Redis5 分钟,只能消费一次SESSIONCookie维持门户控制面的登录状态浏览器 Cookie,内容在 Redis空闲 2 小时OAuth2 Access Token应用调用开放 API调用方 Bearer Token短时有效真正需要记住的是这两条边界:人访问门户:SSO Ticket - Spring Security - Redis Session 应用调用接口:API Key/Secret - OAuth2 Access Token - Gateway我们没有否定 Token,而是没有让同一个门户同时维护 SSO 和自建 JWT 两套登录状态。二、一次完整的 SSO 登录发生了什么整个登录过程涉及浏览器、前端、控制面、Redis、集团 SSO 和数据库。看起来步骤很多,实际上可以归纳为五件事:前端发现用户未登录,发起浏览器顶层 SSO 跳转;后端生成一次性 state,记录用户登录前访问的页面;SSO 登录成功后,带着一次性 Ticket 回调控制面;控制面在服务端验证 Ticket,并把域账号映射为平台账号和角色;控制面创建 Spring Security 登录状态,并保存到 Redis Session。之后每次请求都不再访问集团 SSO。Spring Security 根据SESSIONCookie 从 Redis 恢复当前用户。三、state 到底解决了什么问题很多人第一次看 SSO 代码时,最疑惑的就是 Redis 里的 state。state 不是用户身份,也不是登录凭证。它是