# 第十一章:单点登录(SSO)与联邦身份 > "一次登录,处处访问 — 这是 SSO 的承诺,也是安全工程的挑战。" ```{mermaid} mindmap root((SSO 与联邦身份)) SSO 方式 Cookie SSO Token SSO SAML SSO OIDC SSO SAML 2.0 Assertion SP-Initiated IdP-Initiated 联邦身份 信任关系 身份映射 跨组织 方案对比 Keycloak Okta Azure AD ``` ## 11.1 SSO 解决什么问题 在没有 SSO 的世界里,用户需要为每个应用维护独立的账号和密码: ``` 没有 SSO: 用户 ──▶ App1 (用户名/密码 A) 用户 ──▶ App2 (用户名/密码 B) 用户 ──▶ App3 (用户名/密码 C) → 密码疲劳、弱密码、密码复用 有了 SSO: 用户 ──▶ IdP (一次登录) ──▶ App1 ✅ ──▶ App2 ✅ ──▶ App3 ✅ → 一套凭证、统一管理、更好的安全性 ``` ## 11.2 SSO 实现方式 ### 基于 Cookie 的 SSO(同域) ``` 适用场景:同一顶级域名下的多个子应用 例如:app1.example.com, app2.example.com ┌──────────┐ ┌──────────────┐ │ 用户 │───▶│ auth.example │ │ │ │ .com │ │ │◀───│ Set-Cookie: │ │ │ │ session=xxx │ │ │ │ Domain= │ │ │ │ .example.com │ └──────────┘ └──────────────┘ │ │ Cookie 自动携带到所有 *.example.com ▼ ┌──────────┐ ┌──────────┐ │ app1. │ │ app2. │ │ example │ │ example │ │ .com ✅ │ │ .com ✅ │ └──────────┘ └──────────┘ ``` **局限**:只能在同一顶级域名下使用。 ### 基于 Token 的 SSO(跨域) ``` 适用场景:不同域名的应用 使用 OIDC 或 OAuth2 实现 ┌──────────┐ ┌──────────────┐ │ 用户 │───▶│ IdP │ │ (浏览器) │ │ (Keycloak) │ │ │◀───│ 返回 id_token │ └────┬─────┘ └──────────────┘ │ │ 携带 Token 访问 ├──────────────────▶ app1.com ✅ ├──────────────────▶ app2.org ✅ └──────────────────▶ app3.io ✅ ``` ## 11.3 SAML 2.0 SAML(Security Assertion Markup Language)是企业级 SSO 的标准协议。 ### 核心概念 | 概念 | 说明 | |------|------| | IdP(Identity Provider) | 身份提供者,负责认证用户 | | SP(Service Provider) | 服务提供者,依赖 IdP 的认证结果 | | Assertion | 身份断言,包含用户身份信息 | | Binding | 消息传输方式(HTTP-POST、HTTP-Redirect) | | Metadata | IdP 和 SP 的配置信息(XML 格式) | ### SP-Initiated 流程 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 用户 │ │ SP │ │ IdP │ │ (浏览器) │ │ (应用) │ │ (认证) │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ 1. 访问 SP │ │ │──────────────▶│ │ │ │ 2. 生成 │ │ │ AuthnRequest │ │ 3. 重定向到 IdP │ │◀──────────────│ │ │──────────────────────────────▶│ │ │ 4. 用户登录 │ │ │ │ │ 5. 重定向回 SP(携带 SAML Response) │◀──────────────────────────────│ │──────────────▶│ │ │ │ 6. 验证 │ │ │ Assertion │ │ 7. 登录成功 │ │ │◀──────────────│ │ ``` ### SAML vs OIDC 对比 | 维度 | SAML 2.0 | OIDC | |------|----------|------| | 数据格式 | XML | JSON/JWT | | 传输方式 | HTTP-POST/Redirect | HTTP REST | | Token 大小 | 大(XML) | 小(JWT) | | 移动端支持 | 差 | 好 | | 实现复杂度 | 高 | 低 | | 适用场景 | 企业 SSO | Web/Mobile/API | | 标准组织 | OASIS | OpenID Foundation | | 年代 | 2005 | 2014 | ## 11.4 联邦身份 联邦身份允许不同组织之间建立信任关系,实现跨组织的身份认证: ``` ┌──────────────────┐ ┌──────────────────┐ │ 组织 A │ │ 组织 B │ │ ┌──────────┐ │ 信任 │ ┌──────────┐ │ │ │ IdP A │◀───┼─────────┼───▶│ IdP B │ │ │ │ (Azure AD)│ │ 关系 │ │ (Okta) │ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ │ │ │ ┌────▼─────┐ │ │ ┌────▼─────┐ │ │ │ 用户 A │ │ │ │ 用户 B │ │ │ │ 可以访问 │────┼─────────┼───▶│ 可以访问 │ │ │ │ 组织B资源 │ │ │ │ 组织A资源 │ │ │ └──────────┘ │ │ └──────────┘ │ └──────────────────┘ └──────────────────┘ ``` ### 联邦信任模型 | 模型 | 描述 | 适用场景 | |------|------|---------| | 点对点 | 两个组织直接建立信任 | 合作伙伴 | | Hub-and-Spoke | 中心 IdP 连接多个 SP | 企业集团 | | 网状 | 多个 IdP 互相信任 | 行业联盟 | | 信任框架 | 基于标准的多方信任 | 政府/教育 | ## 11.5 Kerberos 认证协议 Kerberos 是 Windows Active Directory 的核心认证协议: ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 客户端 │ │ KDC │ │ 服务器 │ │ │ │ (密钥分发 │ │ │ │ │ │ 中心) │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ 1. AS-REQ │ │ │ (用户名) │ │ │──────────────▶│ │ │ 2. AS-REP │ │ │ (TGT) │ │ │◀──────────────│ │ │ 3. TGS-REQ │ │ │ (TGT + 服务名)│ │ │──────────────▶│ │ │ 4. TGS-REP │ │ │ (Service Ticket) │ │◀──────────────│ │ │ 5. AP-REQ │ │ (Service Ticket) │ │──────────────────────────────▶│ │ 6. AP-REP │ │ (认证成功) │ │◀──────────────────────────────│ ``` ## 11.6 企业 SSO 方案对比 | 特性 | Keycloak | Okta | Azure AD | |------|----------|------|----------| | 类型 | 开源自托管 | SaaS | SaaS | | 协议 | OIDC/SAML/OAuth2 | OIDC/SAML | OIDC/SAML/WS-Fed | | 成本 | 免费 | 按用户付费 | Microsoft 365 含 | | 自定义 | 高(SPI 扩展) | 中 | 中 | | 用户联邦 | LDAP/AD/Social | 广泛 | AD/B2B/B2C | | MFA | 内置 | 内置 | 内置 | | 部署 | Docker/K8s | 云 | 云 | ### Keycloak Docker 部署 ```bash # 快速启动 Keycloak docker run -d --name keycloak \ -p 8080:8080 \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:latest \ start-dev # 生产部署(PostgreSQL + HTTPS) docker compose up -d ``` ```yaml # docker-compose.yml services: postgres: image: postgres:16 environment: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: keycloak_password volumes: - pgdata:/var/lib/postgresql/data keycloak: image: quay.io/keycloak/keycloak:latest command: start environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak KC_DB_USERNAME: keycloak KC_DB_PASSWORD: keycloak_password KC_HOSTNAME: auth.example.com KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/conf/cert.pem KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/conf/key.pem KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: secure_password ports: - "8443:8443" depends_on: - postgres volumes: pgdata: ``` ## 11.7 小结 - **SSO** 通过一次登录访问多个应用,提升用户体验和安全性 - **SAML 2.0** 是企业级 SSO 标准,但较重;**OIDC** 更现代、更轻量 - **联邦身份** 实现跨组织的身份互信 - **Keycloak** 是最流行的开源 SSO 方案,支持 OIDC/SAML/OAuth2 - 选择 SSO 方案时需考虑:协议支持、部署方式、成本、扩展性