跳到主要内容

JWT Token + Cookie SSO

2025年01月07日
柏拉文
越努力,越幸运

一、认识


在同顶级域下实现 SSO(单点登录) 解决方案,主要是指多个子域名(如 app.example.comportal.example.com)共享同一个身份认证状态,使得用户只需在某一个子域下登录一次,就能在所有子域下访问其他受保护的资源。

二、工作


基于 JWT Token + Cookie 实现同顶级域下 SSO 方案, 并实现 Token 无感刷新, 核心思路是通过一个统一的身份认证服务(Identity Provider,简称 IDP)来处理用户的身份认证,并将认证信息(Token)存储在 Cookie 中,确保不同子域能共享该信息。主要的流程可以分为以下几个步骤:

1. 用户登录认证: 用户首先访问某个子域(如 app.example.com),如果该用户还没有登录,系统会将用户重定向到 认证服务(IDP,通常是一个统一的身份认证服务器。用户在 IDP 系统中进行登录(通常是通过用户名和密码),认证通过后,IDP 会基于 JWT 生成一个包含用户信息的 Access Token 和用于重新生成 Access TokenRefresh Token。将 Access Token 存储在 Cookie 中, 并加上 HttpOnlySecure 保护,防止 JS 获取和防止中间人攻击。将 Refresh Token 存储到 Redis 中, Refresh Token 通常会设置较长的有效期(如 7 天)。设置 Cookie Domain=.example.com,这意味着该 Cookie 可以在 example.com 下的所有子域间共享。在同顶级域下,所有子域名共享一个主域名(如 .example.com),因此,可以通过设置 CookieDomain 属性来让 Cookie 在多个子域间共享。以下是对 Cookie 配置的解释:

  • Secure:确保 Cookie 只能通过 HTTPS 协议传输,增强安全性。

  • HttpOnly:防止客户端 JavaScript 直接访问 Cookie,从而降低 XSS 攻击的风险。

  • SameSite=None:允许跨域请求时发送 Cookie,解决跨子域的 Cookie 问题。

  • Domain=.example.com:确保 Cookie 对所有子域(如 app.example.comportal.example.com)有效。

2. 用户后续请求验证: 用户访问 portal.example.com 或其他子域时,浏览器会自动将存储在 Cookie 中的 Access Token 发送给该子域。子域的后端服务会从请求中提取出 Access Token,并将其发送到身份认证服务(IDP)进行验证。如果 Access Token 有效,认证通过,用户可以继续访问资源。后端服务会将验证结果返回给前端,或者直接允许用户访问需要的资源。如果 Access Token 过期,身份认证服务(IDP)会尝试从 Redis 获取 Refresh Token 并验证其有效性。如果 Refresh Token 有效,身份认证服务(IDP)会尝试使用 Refresh Token 来刷新 Access Token 并返回新的 Access Token。如果 Refresh Token 无效或过期,则返回 401 错误,要求前端重新登录。

3. 用户退出登录: 当用户退出登录时,前端应用会清除浏览器中存储的认证 Access Token(通常是删除 Cookie) 和身份认证服务(IDPRedis 中的 Refresh Token。如果需要,IDP 还可以实现全局注销,即用户退出登录时,不仅仅是在当前子域下登出,还会在所有子域中登出(例如清除所有子域下的 Cookie)。