易君召
易君召
发布于 2026-07-31 / 1 阅读
0
0

用户认证集成单点登录 (SSO) 完整方案

一、先理清核心概念

单点登录 SSO:用户一次登录,即可访问多个相互信任的系统,无需重复输入账号密码。

主流标准协议:

  1. OAuth2.0:授权协议(不负责认证,常配合 OpenID Connect)

  2. OIDC(OpenID Connect 1.0)最推荐现代方案,基于 OAuth2 封装的身份认证协议,互联网、企业应用首选

  3. SAML2.0:传统企业 SSO(政企、老系统、国内外厂商对接常用,XML 格式,偏重内网)

  4. CAS:老牌轻量 SSO,互联网使用越来越少

选型建议:

✅ 面向 Web / 移动端、新项目 → OIDC

✅ 对接政企老系统、国外厂商、政务平台 → SAML2.0

❌ 不要单独只用 OAuth2.0 做登录(OAuth 只是授权,无法拿到可信用户身份)

二、两种典型架构模式

模式 1:中心化身份提供商架构(标准 SSO 架构,90% 场景使用)

  • IdP(身份提供方):统一登录中心,保管账号密码、完成登录认证

    开源选型:Keycloak、Casdoor、Authelia、Auth0、Okta

  • SP(服务提供方):你的业务系统(需要接入 SSO 的应用)

流程(OIDC Authorization Code 主流流程):

  1. 用户访问业务系统 (SP) 受保护接口 / 页面

  2. SP 检测未登录,重定向至 IdP 统一登录页

  3. 用户在 IdP 完成账号密码 / 验证码 / 扫码登录

  4. IdP 生成授权码,回调跳转回 SP

  5. SP 后端使用授权码向 IdP 换取 ID Token(身份凭证 JWT)+ Access Token

  6. SP 解析 ID Token,校验签名、有效期,获取用户唯一标识(sub)

  7. 本地完成账号绑定(首次登录),创建业务会话,登录成功

  8. 用户访问其他接入同一 IdP 的系统,无需再次登录

模式 2:跨系统共享 Cookie(不推荐!仅限同根域名)

仅适用所有应用 *.shturl.,浏览器同源策略限制严重,跨域名完全失效,生产环境尽量抛弃,优先标准协议 SSO。

三、落地实现步骤(以最通用 OIDC 为例)

步骤 1:选择部署 IdP

开源免费推荐 Keycloak(Java 生态友好,支持 SpringBoot、Vue、微服务,同时支持 OIDC/SAML)

轻量选型:Casdoor(Go 开发,部署简单,界面现代化)

步骤 2:IdP 侧配置

  1. 在 IdP 新建客户端(Client)

  2. 设置回调地址 (redirect_uri):业务系统接收回调的接口地址(必须严格匹配)

  3. 选择授权类型:authorization_code(授权码模式,Web 应用标准)

  4. 开启 PKCE(前后端分离 SPA 项目必须开启,防止安全风险)

  5. 获取核心配置参数:

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 示例思路)

  1. 未登录拦截器 → 构建 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 攻击,回调时校验

  1. IdP 回调 /sso/callback

    获取参数:codestate

    • 校验 state 和下发时一致

    • 使用 code POST 请求 token_endpoint,换取 ID Token (JWT)

  2. 校验 ID Token(最重要安全环节)

    • 从 IdP jwks_uri 下载公钥

    • 验证 JWT 签名、过期时间 exp、签发者 iss、受众 aud (客户端 ID)

      ❌ 禁止关闭签名校验!禁止本地静态公钥硬编码(IdP 密钥轮换会失效)

  3. 用户账号关联逻辑

    • 从 token 解析 sub(IdP 侧用户唯一标识,全局唯一)

    • 查询本地数据库:是否存在绑定 sub 的业务账号

      • 存在 → 直接登录,创建 session

      • 不存在 → 自动注册 / 跳转账号绑定页面(业务自定义策略)

步骤 4:前后端分离特殊处理

SPA(Vue/React)不要存储 client_secret,启用 PKCE 挑战码模式

两种接入方式:

  1. 前端 SDK(oidc-client-js)完成跳转、回调,拿到 token 传递给后端校验

  2. 回调逻辑统一交给后端处理(更安全,推荐企业项目)

四、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 校验。

五、关键安全注意事项(极易踩坑)

  1. 永远后端校验 JWT 签名,前端只能保存 token,不能信任前端解析结果

  2. 使用 HTTPS,禁止 HTTP 传输,防止 token 劫持

  3. 开启 PKCE,避免授权码劫持

  4. state 随机值,防止 CSRF 攻击

  5. ID Token 短期有效(5~15 分钟),不要长期存储

  6. 实现登出联动:单点登出(IdP 发起登出通知所有 SP,或前端清除所有系统会话)

    • OIDC 支持 end_session_endpoint 实现全局退出

  7. 不要直接信任 token 内手机号、邮箱,敏感信息建议 IdP 签名 + 后端校验

  8. 多租户场景注意区分不同租户的用户 sub

六、常见扩展场景

场景 1:自有账号系统,不想额外部署 Keycloak

两种选择:

  1. 在现有认证服务上自研实现 OIDC 协议(开发量大,不推荐)

  2. 现有认证中心对接 Casdoor,复用原有账号数据库

场景 2:第三方应用登录(微信 / 钉钉 / 企业微信登录)

本质也是 OAuth2/OIDC,可以统一接入到 IdP,实现:统一门户,兼容内部账号 + 第三方社交登录。

场景 3:SAML2.0 对接外部政企系统

流程和 OIDC 不同,使用 XML 断言;Keycloak 同样同时支持作为 SAML IdP/SP。

七、技术栈选型对比

方案

适用场景

优点

缺点

Keycloak

Java 生态、企业级、微服务

功能齐全、支持 OIDC/SAML、权限管理

内存占用偏高

Casdoor

轻量化、多语言、快速部署

部署简单,支持多第三方登录

社区规模小于 Keycloak

自研 OIDC 服务

高度定制、极致轻量化

可控性强

安全风险高、协议细节容易出错

Auth0/Okta(云服务)

不想运维 IdP

免运维

商业化收费,数据存在第三方

八、最简集成架构图

九、可选落地路线建议

  1. 新项目 / 微服务:部署 Keycloak 作为统一 IdP,所有业务系统通过 OIDC 接入

  2. 中小型项目、不想重运维:Casdoor

  3. 对接外部政务 / 外企系统:提前确认协议是 SAML2.0 还是 OIDC

  4. 老旧单体系统:优先使用自研回调接口对接,避免大规模改造认证模块


评论