本文档指导第三方应用系统通过 CAS 协议接入零信任平台的 SSO 单点登录服务。
适用于所有需要接入 SSO 单点登录的 Web 应用(包括经过网关的应用和 SaaS 应用直连)。
| 场景 | 描述 | 适用情况 |
|---|---|---|
| 场景一:经过网关 | 应用部署在网关后面,用户流量经过网关反向代理 | 内网应用、私有化部署 |
| 场景二:SaaS 直连 | 应用独立部署,用户浏览器直接访问应用域名 | SaaS 应用、公网独立部署 |
两种场景的 API 调用方式完全一致,区别仅在于网络链路是否经过网关。
阅读时请关注与你场景匹配的架构图和流程图即可。
| 角色 | 说明 | 示例 |
|---|---|---|
| 资源拥有者 | 终端用户(在 SSO 上拥有账号) | 员工张三 |
| 零信任网关(场景一) | 反向代理,用户流量经过网关 | gateway.example.com |
| SSO 授权服务 | CAS 认证中心 (IdP) | sso.example.com |
| 应用系统 | 需要接入 SSO 的第三方 Web 应用 | app.example.com |
┌──────────────────────────────────┐
│ 零信任网关 │
│ ┌────────────────────────────┐ │
┌──────────┐ HTTPS │ │ SSO 授权服务 │ │
│ 用户浏览器 │ ◄──────────────────► │ │ sso.example.com │ │
└──────────┘ │ └────────────────────────────┘ │
│ ┌────────────────────────────┐ │
│ │ 应用域名反向代理 │ │
│ │ app.example.com ──► 10.x:8080 │
│ └────────────────────────────┘ │
└──────────────────────────────────┘
│
│ 内网
▼
┌─────────────┐
│ 应用后端服务 │
│ 10.x.x.x:8080│
└─────────────┘用户的所有请求都经过零信任网关。网关将 app.example.com的流量代理到内网的应用后端。
┌──────────┐ HTTPS ┌─────────────────┐
│ 用户浏览器 │ ◄────────────► │ 应用系统 │
└──────────┘ │ app.example.com │
│ └───────┬─────────┘
│ │ HTTPS(后端服务器间通信)
│ HTTPS ▼
└──────────────────► ┌─────────────────┐
│ SSO 授权服务 │
│ sso.example.com │
└─────────────────┘SaaS 应用直接暴露在公 网,用户浏览器直接访问应用域名,不经过零信任网关。
应用后端直接通过 HTTPS 与 SSO 服务通信。
ticket 的地址。(注意: 在应用向 IdP 发起请求时,系统会验证 service 参数中的域名是否和此处配置的应用回调地址中的域名一致)。两种场景的核心逻辑相同: 浏览器 302 → SSO 登录认证 → ticket 回调 → 后端验证 ticket → 获取用户信息。
区别仅在于场景一的每一步都经过网关代理,场景二则由浏览器直接与应用/SSO 通信。
| 步骤 | 发起方 | 说明 |
|---|---|---|
| ① | 用户 | 用户通过浏览器访问应用域名 app.example.com |
| ②③④ | 应用 | 应用检测到用户未登录,302 重定向浏览器到 SSO 登录页 sso.example.com/cas/login?service=... |
| ⑤~⑧ | 用户/SSO | 用户在 SSO 页面上完成身份认证(输入账号密码等) |
| ⑨~⑫ | SSO | 认证通过后,SSO 生成 ticket 票据,302 重定向回应用的 回调地址并携带 ticket 参数 |
| ⑬⑭ | 网关/应用 | 携带 ticket 的回调到达应用后端(场景一经网关代理,场景二直达) |
| ⑮ | 应用后端 | 后端用 ticket + service 直接调用 SSO 的 serviceValidate 接口验证票据 |
| ⑯ | SSO | SSO 返回 XML 格式的认证结果,包含用户详细信息 |
| ⑰⑱ | 应用 | 应用解析 XML 响应中的用户信息,完成本地登录(创建会话、设置 Cookie 等) |
核心概念: 步骤 ⑮⑯ 是服务器间通信——应用后端直接请求 SSO 服务的 HTTPS 接口, ticket验证过程不经过浏览器,保证了认证的安全性。
CAS 与 OAuth 的关键区别: CAS 协议不需要 client_id/client_secret,认证凭据更简单CAS 使用一次性 ticket(而非code+access_token两步换取)CAS 的用户信息在 serviceValidate接口直接返回 XML 格式(而非 JSON)CAS 的 service参数类似于 OAuth 的redirect_uri,必须与后台配置一致
以下 API 两种场景通用,调用方式完全一致。
https://sso.example.com/cas/loginGET| 参数 | 必填 | 类型 | 示例 | 说明 |
|---|---|---|---|---|
service | ✅ | string | https://app.example.com/cas/callback | 应用的回调地址,需要进行 urlencode,系统会验证该地址合法性。 |
https://sso.example.com/cas/login?service=https%3A%2F%2Fapp.example.com%2Fcas%2Fcallbackticket 票据:302 重定向到 https://app.example.com/cas/callback?ticket=ST-hd67cYLohcJOiwTUs7ba6HUazO7hticket 直接通过服务器之间调用 SSO。https://sso.example.com/cas/serviceValidateGET| 参数 | 必填 | 类型 | 示例 | 说明 |
|---|---|---|---|---|
ticket | ✅ | string | ST-hd67cYLohcJOiwTUs7ba6HUazO7h | 传入回调接口中接收到的 ticket 票据 |
service | ✅ | string | https://app.example.com/cas/callback | 必须与获取 ticket 时的 service 保持完全一致,且同样需 urlencode |
https://sso.example.com/cas/serviceValidate?ticket=ST-hd67cYLohcJOiwTUs7ba6HUazO7h&service=https%3A%2F%2Fapp.example.com%2Fcas%2Fcallbackticket 校验成功时,将返回如下 XML 格式包含用户详细信息的响应包:<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
<cas:authenticationSuccess>
<cas:user>zhangsan</cas:user>
<cas:attributes>
<cas:surname>张</cas:surname>
<cas:cname>张三</cas:cname>
<cas:givenname>三</cas:givenname>
<cas:mail>zhangsan@example.com</cas:mail>
<cas:mobile>+8619046547896</cas:mobile>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>ticket 不存在或已失效,认证中心将返回错误消息:<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
<cas:authenticationFailure cas:code="INVALID_TICKET">ticket not exist</cas:authenticationFailure>
</cas:serviceResponse>注意: 解析 XML 后,应用可提取 <cas:user>或其attributes节点的内容与本地账户体系映射,完成最后的单点登录并控制授权访问。
<cas:user> 中的用户名在本地数据库中查找对应用户📌 代码说明 以下代码示例完整展示了 CAS 协议对接的核心逻辑,可直接用于开发参考。 Java 示例:展示 Spring Boot Controller 核心代码,需在已有 Spring Boot 项目中使用。 Go 示例:完整可运行程序,直接 go run main.go启动。Python 示例:完整可运行程序, pip install flask requests后直接启动。所有示例中的 sso.example.com、app.example.com等配置需替换为实际值。
内网环境使用自签证书时,示例已包含跳过 TLS 校验的配置。
⛔ 安全风险警告 启用逃生机制(降级到本地密码登录)意味着绕过了 SSO 的统一认证和多因素验证(MFA)。
这可能带来以下安全风险:本地账号密码不受零信任策略保护(无 MFA、无设备检查、无地理围栏) 如果本地密码泄露,攻击者可直接登录,不会被 SSO 侧的异常检测拦截 审计日志中将缺少 SSO 登录事件,可能影响安全审计的完整性 使用建议: 1.逃生机制仅限 SSO 完全不可用时的应急使用,恢复后应立即关闭 2.本地管理员账号应设置高强度密码并定期轮换 3.建议记录所有本地登录事件并设置告警,确保逃生期间的操作可审计
用户访问 → 检查 SSO 状态 → SSO 可用?
├── 是 → 正常 CAS SSO 登录
└── 否 → 降级到本地账号密码登录integration_configs.enabled = 0)最佳实践: 无论是否启用了 SSO,始终保留至少一个 本地管理员账号(有密码),
确保在 SSO 完全不可用时,仍有人可以登录系统进行故障处理。
service 参数的域名一致)sso.example.com/cas/login?service=... 跳转 URLservice 参数已做 URL 编码ticket 参数serviceValidate 接口的 service 参数与获取 ticket 时完全一致authenticationSuccess 和 authenticationFailure 两种情况ticket 验证在后端完成,不暴露给前端 JavaScriptservice 不匹配时有明确错误提示ticket 过期或重复使用时有明确错误处理serviceValidate 返回 INVALID_TICKET 错误?ticket 是一次性的,不能重复使用ticket 有效期很短,收到后需尽快调用 serviceValidateservice 参数必须与获取 ticket 时完全一致(包含协议、域名、路径、URL 编码)service 参数中的域名与后台配置的回调地址域名一致cas: 前缀。getElementsByTagName("cas:user") 或配置 namespace-aware 的 DocumentBuilderns = {'cas': 'http://www.yale.edu/tp/cas'} 命名空间映射xml:"authenticationSuccess" 标签(Go 的 xml 包会自动处理命名空间)serviceValidate 是后端服务器间通信,建议直连 SSO 服务(不经过网关),这样即使网关出现负载问题,后端验证仍能正常工作。确保后端网络可以直达 SSO 服务地址即可。| 维度 | CAS | OAuth2.0 |
|---|---|---|
| 复杂度 | 简单(2 步:跳转 + 验 ticket) | 较复杂(3 步:跳转 + 换 token + 取用户信息) |
| 凭证管理 | 无需 client_id/secret | 需要 client_id + client_secret |
| 数据格式 | XML | JSON |
| 令牌刷新 | 不支持 | 支持 refresh_token |
| 适用场景 | 纯 SSO 认证 | SSO + API 授权 |
如果只需要 SSO 单点登录,CAS 更简单;如果还需要 API 授权能力,选择 OAuth2.0。