一、OAuth2 实现 SSO 的核心流程(深度拆解)
单点登录的本质是「一次认证、多系统共享认证状态」,OAuth2 通过授权码模式(Authorization Code) 实现 SSO 是行业主流方案,下面分步骤拆解完整流程(结合角色交互):
核心角色回顾
| 角色 | 示例 | 核心职责 |
|---|---|---|
| 认证服务器(AS) | http://localhost:8080 | 统一登录入口、颁发 Token、验证 Token |
| 资源服务器 1(RS1) | http://localhost:8081 | 业务系统 A(如订单系统) |
| 资源服务器 2(RS2) | http://localhost:8082 | 业务系统 B(如用户系统) |
| 终端用户(User) | 普通登录用户 | 提供账号密码完成认证 |
| 客户端(Client) | RS1/RS2 | 接入 SSO 的应用,代表用户向 AS 申请授权 / Token |
完整流程(授权码模式)
关键步骤解析
- 重定向授权请求 :资源服务器检测到用户未登录时,会拼接
client_id(客户端标识)、response_type=code(授权码模式)、redirect_uri(回调地址)等参数,重定向到认证服务器的授权端点。 - 用户认证:认证服务器展示统一登录页,用户输入账号密码,服务器验证通过后创建会话(Session),标记用户已登录。
- 颁发授权码:认证服务器生成一次性、短期有效的授权码(code),重定向回资源服务器的回调地址。
- 兑换 Token :资源服务器后台用授权码 + 客户端密钥,向认证服务器兑换
Access Token(访问令牌)和Refresh Token(刷新令牌)。 - SSO 核心:用户访问其他资源服务器时,认证服务器通过会话识别用户已登录,直接颁发授权码,资源服务器兑换 Token 后完成认证,无需用户重复登录。
二、OAuth2 的安全性保障措施(博客重点)
OAuth2 本身是授权框架,若配置不当极易引发安全漏洞,下面从核心风险 和防护措施两方面讲解,让你的博客更有深度。
1. 核心安全风险
- Token 泄露:Access Token 被窃取,攻击者可冒充用户访问资源;
- 授权码劫持:授权码被中间人拦截,兑换 Token 后冒充客户端;
- 客户端伪装:恶意应用冒充合法客户端接入认证服务器;
- Token 过期失控:Token 有效期过长,泄露后危害大;
- 未加密传输:HTTP 传输导致敏感信息(如密码、Token)被监听。
2. 关键防护措施
2.1 传输层加密:强制使用 HTTPS
- 核心要求:认证服务器、资源服务器的所有接口(尤其是授权、Token、用户信息接口)必须使用 HTTPS;
- 原因:HTTPS 通过 TLS/SSL 加密传输数据,防止中间人攻击、数据监听;
- Java 实现:在 Spring Boot 中配置 HTTPS(示例):
2.2 严格管控授权码(Code)
- 一次性使用:授权码只能兑换一次 Token,兑换后立即失效(Spring Security OAuth2 默认实现);
- 短期有效:授权码有效期控制在 10-60 秒内,减少劫持风险;
- 绑定客户端 :授权码必须与
client_id、redirect_uri绑定,防止跨客户端使用; - 防 CSRF :授权请求中添加
state参数(随机字符串),客户端验证回调的state是否一致,防止 CSRF 攻击。
2.3 Token 安全策略
- Access Token 短期化:有效期建议 1 小时内(如 3600 秒),泄露后危害窗口小;
- Refresh Token 安全存储 :
- 服务端:Refresh Token 存储到 Redis,关联用户 + 客户端,支持手动吊销;
- 客户端:前端存储在 HttpOnly Cookie 中(防止 JS 窃取),后端存储在服务器端;
- Token 吊销机制:提供 Token 注销接口,用户登出 / 账号异常时立即吊销 Token;
- 避免 Token 明文传输 :Token 仅在 HTTP Header 中传递(如
Authorization: Bearer <token>),禁止放在 URL 中(易被日志、浏览器历史记录记录)。
2.4 客户端身份验证
- 客户端密钥加密存储 :客户端
client_secret绝不能明文存储,需用 BCrypt 等算法加密(如代码中BCryptPasswordEncoder); - 限制回调地址 :
redirect_uri必须在认证服务器白名单中,禁止使用通配符(如http://*); - 区分客户端类型 :
- 机密客户端(如后端应用):使用
client_secret认证; - 公共客户端(如前端 / APP):不存储
client_secret,改用 PKCE(Proof Key for Code Exchange)机制。
- 机密客户端(如后端应用):使用
2.5 权限最小化
- Scope 精细化 :为不同客户端分配最小必要权限(如订单系统仅授权
order:read,而非all); - 角色控制:结合 Spring Security 的 RBAC,限制用户可访问的资源。
2.6 日志与监控
- 审计日志 :记录所有授权、Token 兑换、Token 验证操作,包含
client_id、用户 ID、IP、时间等; - 异常监控:监控高频 Token 兑换、异常 IP 访问、授权码多次使用等行为,及时告警。
2.7 进阶防护:JWT + 签名 / 加密
- 若使用 JWT 作为 Token 格式,需:
- 采用非对称加密(RSA)签名,防止 Token 被篡改;
- 敏感字段(如用户 ID)加密存储,避免 Token 解码后泄露信息;
- 禁止在 JWT 中存储密码、手机号等敏感信息。
总结
- OAuth2 实现 SSO 的核心是授权码模式,通过统一认证服务器颁发 Token,所有资源服务器共享 Token 认证状态,关键是保证 Token 的共享性和有效性;
- Java 中基于 Spring Security OAuth2 实现 SSO 时,需重点配置认证服务器(Token 颁发)、资源服务器(Token 验证),并将 Token 存储到 Redis 以支持多实例部署;
- OAuth2 的安全性核心是「传输加密 + 短期 Token + 严格的客户端验证 + 权限最小化」,必须强制使用 HTTPS,管控授权码和 Token 的生命周期,避免配置漏洞。