单点登录 (SSO)

SSO 把认证能力集中到可信中心,业务系统不碰密码,只认中心签发的身份结果。认证集中、协议标准、会话分层、授权解耦。

#type / synthesis #status / evergreen #tech / security #tech / dev / backend

[!info] related notes

单点登录 (SSO)

一句话核心

SSO 不是”用户只登一次”,而是把认证能力集中到一个可信中心,业务系统自己不碰密码,只认这个中心签发的身份结果。

三层架构

职责
身份认证层验证用户名密码、短信、企业微信、AD、MFA
身份断言层验证后如何安全告诉各系统”这个人是谁”
业务会话层各子系统如何建立自己的登录态

SSO 解决什么问题

  1. 认证统一:用户不用在 A/B/C 系统分别输密码
  2. 身份信任传递:A 系统相信认证中心说”这个用户已登录”

不等于权限统一。 SSO 只证明”你是谁”(Authentication),“你能看什么”是授权系统的事(Authorization)。

参与方角色

角色别名职责
用户端浏览器、App、小程序
认证中心IdP / Auth Server / SSO Server登录认证、签发票据、维护全局登录态、MFA、对接 LDAP/AD/企微
业务系统SP / Client / Relying Party发现未登录→跳转认证中心→校验结果→建立本地会话
用户目录数据库 / LDAP / AD / 企业微信

协议选型

协议适合特点
oidc现代 Web/App/API基于 OAuth2,id_token/access_token/refresh_token,开发体验好
saml老企业系统、政企、SaaS 联邦XML 断言,浏览器重定向/POST,企业集成多但开发体验不如 OIDC
CAS传统内部门户、高校中央票据模型清晰,现代生态不如 OIDC

结论:新系统优先 OIDC,老企业联邦可能需 SAML,长期向 OIDC 收敛。 不要自己发明协议。

标准登录流程(OIDC 授权码模式)

用户 → 业务系统A: 访问资源
业务系统A → 用户: 跳转到 SSO(带 state/nonce/redirect_uri)
用户 → SSO: 带上 SSO Cookie
SSO → 用户: 未登录→展示登录页 / 已登录→直接签发 code
用户 → 业务系统A: 带 code 回调
业务系统A → SSO: 用 code 换 token(后端调用)
SSO → 业务系统A: 返回 id_token/access_token/refresh_token
业务系统A: 校验 id_token(签名/iss/aud/exp/nonce)
业务系统A → 用户: 建立本地 session cookie

第二次访问业务系统 B 时: B 跳去 SSO → SSO 发现全局会话还在 → 直接签发 code → B 建立本地 session → 用户无感登录。

两层会话

会话存储位置证明什么
全局 Sessionsso.example.com 域下用户在统一认证中心已登录
本地 Sessionapp1.example.com 各自域下这个系统自己认可该用户已登录

关键设计对象

用户身份标识

  • user_id(sub):内部唯一主键,不变
  • username:登录名,可改
  • display_name:展示名,可改

不要拿手机号、邮箱当永远不变主键。

Token 三类

Token用途建议
id_token身份信息(你是谁)短效,含 iss/sub/aud/exp/nonce
access_token调用 API 鉴权更短效,不塞太多业务权限
refresh_token续签可撤销、可轮换

用户体系

  • users 表:用户主信息
  • user_identities 表:外部身份映射(password / ldap / wechat / dingding → 同一个 user_id)
  • orgs / roles / user_roles:组织与权限

单点登出

方式效果
本地登出只删业务系统 session,不动 SSO 全局 session
全局登出销毁 SSO 全局 session + 通知各业务系统清理本地 session

通知方式:前端跳转式 / 后端 back-channel 回调式 / 消息总线事件驱动。

安全必做

  • HTTPS 强制
  • state 防 CSRF,nonce 防重放
  • redirect_uri 精确白名单匹配
  • PKCE 用于 public client(SPA/原生 App)
  • 登录限频、设备指纹风控、图形验证码
  • 登录成功后轮换 session id
  • JWT 签名校验 + key rotation
  • 敏感信息不明文塞 token
  • 不要将 access_token 存 localStorage(用 HttpOnly cookie)

常见坑

后果
业务系统自己也存密码破坏统一认证
redirect_uri 校验不严格重定向劫持
access_token 存 localStorageXSS 拿走
JWT 一发就不管无法撤销/登出失效
没有统一登出链路用户以为退出了,其他系统还在线
所有权限塞 token权限一变旧 token 还在飞
依赖 iframe 第三方 cookie现代浏览器越来越不可靠

推荐落地方案

  • 协议:首选 OIDC,兼容老系统补 SAML
  • 登录方式:用户名密码 + 企微/钉钉扫码 + MFA + LDAP/AD
  • 会话:SSO 全局 session 存 Redis,业务系统各自维护本地 session,关联 sso_session_id
  • Token:id_token 短效,access_token 更短效,refresh_token 可撤销轮换
  • 登出:支持 local + global logout,推荐 back-channel logout
  • 安全:HTTPS + PKCE + state/nonce + 精确 redirect_uri + 风控限流 + 审计日志 + 密钥轮换

架构判断 7 问

  1. 用户身份唯一主键是什么?
  2. 全局 session 和本地 session 分别在哪?
  3. 用的是什么标准协议?
  4. redirect_uri / state / nonce / PKCE 是否正确实现?
  5. 单点登出怎么做?
  6. 权限归 SSO 还是业务系统?边界清不清晰?
  7. 密钥、审计、风控、限流有没有闭环?
创建于 2026/4/1 更新于 2026/5/27