一、先理清核心概念
单点登录 SSO:用户一次登录,即可访问多个相互信任的系统,无需重复输入账号密码。
主流标准协议:
OAuth2.0:授权协议(不负责认证,常配合 OpenID Connect)
OIDC(OpenID Connect 1.0):最推荐现代方案,基于 OAuth2 封装的身份认证协议,互联网、企业应用首选
SAML2.0:传统企业 SSO(政企、老系统、国内外厂商对接常用,XML 格式,偏重内网)
CAS:老牌轻量 SSO,互联网使用越来越少
选型建议:
✅ 面向 Web / 移动端、新项目 → OIDC
✅ 对接政企老系统、国外厂商、政务平台 → SAML2.0
❌ 不要单独只用 OAuth2.0 做登录(OAuth 只是授权,无法拿到可信用户身份)
二、两种典型架构模式
模式 1:中心化身份提供商架构(标准 SSO 架构,90% 场景使用)
IdP(身份提供方):统一登录中心,保管账号密码、完成登录认证
开源选型:Keycloak、Casdoor、Authelia、Auth0、Okta
SP(服务提供方):你的业务系统(需要接入 SSO 的应用)
流程(OIDC Authorization Code 主流流程):
用户访问业务系统 (SP) 受保护接口 / 页面
SP 检测未登录,重定向至 IdP 统一登录页
用户在 IdP 完成账号密码 / 验证码 / 扫码登录
IdP 生成授权码,回调跳转回 SP
SP 后端使用授权码向 IdP 换取 ID Token(身份凭证 JWT)+ Access Token
SP 解析 ID Token,校验签名、有效期,获取用户唯一标识(sub)
本地完成账号绑定(首次登录),创建业务会话,登录成功
用户访问其他接入同一 IdP 的系统,无需再次登录
模式 2:跨系统共享 Cookie(不推荐!仅限同根域名)
仅适用所有应用 *.shturl.,浏览器同源策略限制严重,跨域名完全失效,生产环境尽量抛弃,优先标准协议 SSO。
三、落地实现步骤(以最通用 OIDC 为例)
步骤 1:选择部署 IdP
开源免费推荐 Keycloak(Java 生态友好,支持 SpringBoot、Vue、微服务,同时支持 OIDC/SAML)
轻量选型:Casdoor(Go 开发,部署简单,界面现代化)
步骤 2:IdP 侧配置
在 IdP 新建客户端(Client)
设置回调地址 (redirect_uri):业务系统接收回调的接口地址(必须严格匹配)
选择授权类型:
authorization_code(授权码模式,Web 应用标准)开启 PKCE(前后端分离 SPA 项目必须开启,防止安全风险)
获取核心配置参数:
plaintext
issuer: https://sso.shturl./realms/business
client_id: your-sp-client
client_secret: xxx(SPA前端项目不要密钥,使用PKCE)
authorization_endpoint 授权地址
token_endpoint 换取token地址
jwks_uri 公钥地址(用于校验JWT签名)
步骤 3:业务系统 (SP) 集成实现(后端核心逻辑)
核心原则:Token 校验必须在后端执行,前端不可校验 JWT 签名!
核心流程伪代码(SpringBoot 示例思路)
未登录拦截器 → 构建 OIDC 授权链接,302 重定向到 IdP 登录页
plaintext
https://sso.shturl./auth?
client_id=xxx
&response_type=code
&redirect_uri=https://your-system.com/sso/callback
&scope=openid profile email
&state=随机防csrf字符串
state 参数:记录当前访问页面,防止 CSRF 攻击,回调时校验
IdP 回调
/sso/callback获取参数:
code、state校验 state 和下发时一致
使用 code POST 请求 token_endpoint,换取 ID Token (JWT)
校验 ID Token(最重要安全环节)
从 IdP
jwks_uri下载公钥验证 JWT 签名、过期时间 exp、签发者 iss、受众 aud (客户端 ID)
❌ 禁止关闭签名校验!禁止本地静态公钥硬编码(IdP 密钥轮换会失效)
用户账号关联逻辑
从 token 解析
sub(IdP 侧用户唯一标识,全局唯一)查询本地数据库:是否存在绑定 sub 的业务账号
存在 → 直接登录,创建 session
不存在 → 自动注册 / 跳转账号绑定页面(业务自定义策略)
步骤 4:前后端分离特殊处理
SPA(Vue/React)不要存储 client_secret,启用 PKCE 挑战码模式
两种接入方式:
前端 SDK(oidc-client-js)完成跳转、回调,拿到 token 传递给后端校验
回调逻辑统一交给后端处理(更安全,推荐企业项目)
四、SpringBoot 快速集成方案
方案 A:Spring Security OAuth2 Resource Server + Client(官方原生支持 OIDC)
依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
直接 yaml 配置即可对接 Keycloak / 任意 OIDC IdP,不用手写回调、token 交换逻辑。
方案 B:自研 SSO 回调接口
适合老旧系统、非 Spring 技术栈(PHP/.Net/Go),自行实现 HTTP 交互、JWT 校验。
五、关键安全注意事项(极易踩坑)
永远后端校验 JWT 签名,前端只能保存 token,不能信任前端解析结果
使用 HTTPS,禁止 HTTP 传输,防止 token 劫持
开启 PKCE,避免授权码劫持
state 随机值,防止 CSRF 攻击
ID Token 短期有效(5~15 分钟),不要长期存储
实现登出联动:单点登出(IdP 发起登出通知所有 SP,或前端清除所有系统会话)
OIDC 支持
end_session_endpoint实现全局退出
不要直接信任 token 内手机号、邮箱,敏感信息建议 IdP 签名 + 后端校验
多租户场景注意区分不同租户的用户 sub
六、常见扩展场景
场景 1:自有账号系统,不想额外部署 Keycloak
两种选择:
在现有认证服务上自研实现 OIDC 协议(开发量大,不推荐)
现有认证中心对接 Casdoor,复用原有账号数据库
场景 2:第三方应用登录(微信 / 钉钉 / 企业微信登录)
本质也是 OAuth2/OIDC,可以统一接入到 IdP,实现:统一门户,兼容内部账号 + 第三方社交登录。
场景 3:SAML2.0 对接外部政企系统
流程和 OIDC 不同,使用 XML 断言;Keycloak 同样同时支持作为 SAML IdP/SP。
七、技术栈选型对比
八、最简集成架构图
%20%E5%AE%8C%E6%95%B4%E6%96%B9%E6%A1%88%E2%80%9401.png)
九、可选落地路线建议
新项目 / 微服务:部署 Keycloak 作为统一 IdP,所有业务系统通过 OIDC 接入
中小型项目、不想重运维:Casdoor
对接外部政务 / 外企系统:提前确认协议是 SAML2.0 还是 OIDC
老旧单体系统:优先使用自研回调接口对接,避免大规模改造认证模块