1. 应用系统SSO对接
标准Open API
  • 管理后台接口
    • 开发前必读
    • 身份管理
      • 用户
        • 校验账号是否存在
        • 人员查询接口
        • 创建账号
        • 用户封禁接口
        • 用户注销接口(当前浏览器登入的会话)
        • 验证用户token是否有效
        • 用户注销登录 (用户所有登入会话包括终端)
        • 批量用户注销登录(标准版本不支持)
        • 获取终端用户在线状态(v4.0.11.8版本及以上可用)
      • 组织架构
        • 从指定用户组中移除指定账号
        • 校验指定用户组中是否有某个账号
        • 添加账号到指定用户组
        • 部门查询接口
    • 应用管理
      • HTTP应用
        • 域名端口存在校验
        • 应用发布
        • 应用更新
        • 删除应用(v4.0.10.3以上)
        • 应用详情(v4.0.10.3以上)
        • 应用列表接口(v4.0.8.0以上)
      • 隧道网关
        • 获取用户sdp网关接入状态
        • 创建隧道应用(v4.0.10.3以上)
        • 更新隧道应用(v4.0.10.3以上)
        • 删除隧道应用(v4.0.10.3以上)
        • 查询隧道应用详情(v4.0.10.3以上)
        • 下线sdp隧道连接(v4.0.12.4以上)
      • 授权管理
        • 添加HTTP应用到指定授权组
        • 授权策略详情(v4.0.10.3以上)
        • 授权策略列表查询(v4.0.10.3以上)
        • 更新授权策略(v4.0.10.3以上)
        • 创建授权策略(v4.0.10.3以上)
    • 主机运维网关
      • 主机组列表
      • 授权主机(主机添加负责人)
    • 终端管理
      • 资产管理
        • (新)删除可信资产(适用版本:4.0.11.0及以上)
        • (新)添加可信资产(适用版本:4.0.11.0及以上)
        • (新)获取可信资产列表(适用版本:4.0.11.0及以上)
        • (旧)删除可信资产(适用版本:4.0.8.0~4.0.10.X)
        • (旧)添加可信资产(适用版本:4.0.8.0~4.0.10.X)
        • (旧)获取可信资产列表(适用版本:4.0.8.0~4.0.10.0X)
      • 终端
        • 客户端注销登录
        • 终端状态信息拉取(4.0.8.1及以上版本支持)
        • 终端状态信息推送接口(4.0.8.1及以上版本支持)
        • 终端推送升级(4.0.11.0以上版本)
    • 组件管理
      • HTTP应用网关
        • 修改网关模式(4.0.8.0及以上版本可用)
        • 网关列表
    • 身份输出
      • 开发必读
      • 用户
        • 用户全量拉取(4.0.8.0及以上版本支持)
        • 用户增量拉取(4.0.8.0及以上版本支持)
      • 组织架构
        • 组织机构增量拉取(4.0.8.0及以上版本支持)
        • 组织机构全量拉取(4.0.8.0及以上版本支持)
    • API接口同步
      • API同步
    • IP地址池
      • 创建IP地址池(v4.0.15.0及以上)
      • 更新IP地址池(v4.0.15.0及以上)
      • 删除IP地址池(v4.0.15.0及以上)
      • 获取IP地址池列表(v4.0.15.0及以上)
  • 应用系统SSO对接
    • 零信任平台 OAuth2.0 协议对接指南
    • 零信任平台Cas协议对接指南
    • 零信任平台JWT协议对接指南
    • 零信任平台简易 SSO 对接指南
  1. 应用系统SSO对接

零信任平台 OAuth2.0 协议对接指南

本文档指导第三方应用系统通过 OAuth2.0 授权码模式接入零信任平台的 SSO 单点登录服务。
适用于所有需要接入 SSO 单点登录的 Web 应用(包括经过网关的应用和 SaaS 应用直连)。
OIDC协议与OAuth2.0的过程一致,只是调用的接口不同,参数也是一致的,接口参见:{SSO授权服务}/oidc/config

一、整体架构#

1.1 场景选择#

请根据你的部署方式选择对应场景:
场景描述适用情况
场景一:经过网关应用部署在网关后面,用户流量经过网关反向代理内网应用、私有化部署
场景二:SaaS 直连应用独立部署,用户浏览器直接访问应用域名SaaS 应用、公网独立部署
两种场景的 API 调用方式完全一致,区别仅在于网络链路是否经过网关。
阅读时请关注与你场景匹配的架构图和流程图即可。

1.2 角色说明#

OAuth2.0 授权码模式涉及以下角色:
角色说明示例
资源拥有者终端用户(在 SSO 上拥有账号)员工张三
零信任网关(场景一)反向代理,用户流量经过网关gateway.example.com
SSO 授权服务OAuth2.0 授权服务器sso.example.com
应用系统需要接入 SSO 的第三方 Web 应用app.example.com

1.3 网络架构#

场景一:经过网关#

                                    ┌──────────────────────────────────┐
                                    │         零信任网关               │
                                    │  ┌────────────────────────────┐  │
  ┌──────────┐     HTTPS            │  │      SSO 授权服务          │  │
  │  用户浏览器 │ ◄──────────────────► │  │   sso.example.com         │  │
  └──────────┘                      │  └────────────────────────────┘  │
                                    │  ┌────────────────────────────┐  │
                                    │  │   应用域名反向代理          │  │
                                    │  │   app.example.com ──► 10.x:8080 │
                                    │  └────────────────────────────┘  │
                                    └──────────────────────────────────┘
                                                    │
                                                    │ 内网
                                                    ▼
                                             ┌─────────────┐
                                             │  应用后端服务  │
                                             │ 10.x.x.x:8080│
                                             └─────────────┘
用户的所有请求都经过零信任网关。网关将 app.example.com 的流量代理到内网的应用后端。

场景二:SaaS 直连(不经过网关)#

  ┌──────────┐     HTTPS      ┌─────────────────┐
  │  用户浏览器 │ ◄────────────► │    应用系统       │
  └──────────┘               │ app.example.com  │
       │                      └───────┬─────────┘
       │                              │ HTTPS(后端服务器间通信)
       │     HTTPS                    ▼
       └──────────────────►  ┌─────────────────┐
                             │  SSO 授权服务    │
                             │ sso.example.com  │
                             └─────────────────┘
SaaS 应用直接暴露在公网,用户浏览器直接访问应用域名,不经过零信任网关。
应用后端直接通过 HTTPS 与 SSO 服务通信。

1.4 应用发布与密钥获取流程#

在应用系统对接前,必须先在 零信任管理后台(如 ztp.example.com)完成应用发布,并获取 OAuth2.0 的相关密钥凭证。完整流程如下:
1.
登录零信任管理后台:使用管理员账号登录 ztp.example.com。
2.
进入 SSO 配置:在左侧导航栏找到 [应用中心/应用发布] -> [SSO 配置]。
3.
选择协议类型:在协议类型下拉菜单中,必须选择 OAuth(不要选择 SAML、CAS 或 JWT)。
4.
配置基本信息与回调地址:
填写应用名称及基本信息。
应用回调地址:填写应用接收 code 的完整 URL(例如 https://app.example.com/oauth2/callback)。这个地址必须与代码中发起的 redirect_uri 完全一致。
5.
配置授权返回字段:勾选应用需要获取的用户信息字段,通常勾选 name、uid、email、mobile(对应对接中的 scope 数值)。
6.
获取密钥凭证:
配置保存后,系统会自动生成 Client ID(应用标识)。
同时系统会提供一份 Client_key(应用密钥)。
注意:务必妥善保存 Client_key,离开此页面后可能无法再次查看明文。

1.5 前置条件#

在完成上述流程后,你将获得以下对接所需的最终凭证:
配置项管理界面字段名API 参数名示例值
应用标识Client IDclient_idAbc123DefGhI456
应用密钥Client_keyclient_secretxK9mN2pL5qR8sT1vW4yA7bC0dE3fH6j
授权范围授权返回字段scopeuid,name,email,mobile
回调地址应用回调地址redirect_urihttps://app.example.com/oauth2/callback
⚠️ 重要: 管理界面上的字段名叫 Client_key,但在 API 调用时参数名必须写 client_secret。
这两个名称指向同一个值,切勿混淆。

二、授权码模式完整流程#

2.1 流程图(场景一:经过网关)#

2.2 流程图(场景二:SaaS 直连,不经过网关)#

两种场景的核心逻辑相同: 浏览器 302 → SSO 认证 → code 回调 → 后端换 token → 获取用户信息。
区别仅在于场景一的每一步都经过网关代理,场景二则由浏览器直接与应用/SSO 通信。

2.3 流程分步说明#

以下步骤编号对应场景一流程图。场景二的逻辑相同,只是去掉了网关中转。
步骤发起方说明
①用户用户通过浏览器访问应用域名 app.example.com
②③④应用应用检测到用户未登录,302 重定向浏览器到 SSO 授权页
⑤~⑧用户/SSO用户在 SSO 页面上完成身份认证(输入账号密码等)
⑨~⑫SSO认证通过后,SSO 生成授权码 code,302 重定向回应用的回调地址
⑬⑭网关/应用携带 code 的回调到达应用后端(场景一经网关代理,场景二直达)
⑮应用后端后端用 code + client_id + client_secret 直接调用 SSO 接口换取 access_token
⑯应用后端后端用 access_token 直接调用 SSO 接口获取用户信息
⑰⑱应用应用根据用户信息完成本地登录(创建会话、设置 Cookie 等)
核心概念: 步骤 ⑮⑯ 是服务器间通信——应用后端直接请求 SSO 服务的 HTTPS 接口,
client_secret 不会暴露给浏览器,保证了密钥安全。

三、API 接口详细说明#

3.1 Step 1:获取授权码#

此请求由用户浏览器发起(302 重定向),不涉及应用后端。
请求方式: GET(浏览器地址栏跳转)
GET {SSO地址}/oauth2.0
    ?response_type=code
    &client_id={client_id}
    &redirect_uri={回调地址,需 URL 编码}
    &scope={授权范围}
    &state={自定义状态值}
参数说明:
参数必填类型说明
response_type✅string固定值 code
client_id✅string在管理后台获取的应用标识
redirect_uri✅string回调地址,必须做 URL 编码,且必须与管理后台配置 完全一致
scope✅string授权范围,多个字段用 逗号 分隔:uid,name,email,mobile
state建议string随机字符串,用于 CSRF 防护。SSO 会在回调时原样返回此值
完整示例:
https://sso.example.com/oauth2.0
    ?response_type=code
    &client_id=Abc123DefGhI456
    &redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth2%2Fcallback
    &scope=uid,name,email,mobile
    &state=a1b2c3d4e5f6
成功响应: 用户完成认证后,浏览器被 302 重定向到:
https://app.example.com/oauth2/callback?code=AUTHORIZATION_CODE_HERE&state=a1b2c3d4e5f6

3.2 Step 2:换取访问令牌(access_token)#

此请求由应用后端发起,直接调用 SSO 服务接口。
请求方式: GET
⚠️ 关键注意:此接口仅支持 GET 方式。 使用 POST(无论 form 还是 JSON)都会导致认证失败或返回 HTML 页面。
GET {SSO地址}/oauth2.0/token
    ?client_id={client_id}
    &client_secret={client_secret}
    &grant_type=authorization_code
    &scope={scope}
    &redirect_uri={redirect_uri,需 URL 编码}
    &code={上一步获取的授权码}
参数说明:
参数必填类型说明
client_id✅string应用标识
client_secret✅string应用密钥(管理界面上叫 Client_key,参数名必须写 client_secret)
grant_type✅string固定值 authorization_code
scope✅string与 Step 1 中一致
redirect_uri✅string与 Step 1 中一致,需 URL 编码
code✅stringStep 1 回调中获取的授权码,一次性使用
成功响应(HTTP 200):
{
    "access_token":  "MZVLNTG4MWITMJGXNY0ZMZRMLTG1ODETYZFKMDFMMWM5NGEZ",
    "expires_in":    7200,
    "refresh_token": "NDQ5ZMI0ZJMTMWU2YI01ZGQ2LTHKNGETNJCYMMM3Y2I5NDY2",
    "scope":         "name,uid,email,mobile",
    "token_type":    "Bearer"
}
字段类型说明
access_tokenstring访问令牌,用于下一步获取用户信息
expires_inint有效期(秒),通常 7200(2 小时)
refresh_tokenstring刷新令牌,用于续期(可选实现)
scopestring实际授权的范围
token_typestring固定值 Bearer
错误响应(HTTP 200):
{
    "error": "invalid_grant",
    "error_description": "The provided authorization grant is invalid, expired, revoked..."
}
常见错误及排查:
错误码含义排查方法
invalid_clientClient 认证失败① 检查 client_id/client_secret 是否正确 ② 确认使用了 GET 方式(非 POST) ③ 确认参数名是 client_secret(非 client_key)
invalid_grant授权码无效或已过期① code 是一次性的,不能重复使用 ② code 有效期很短,需尽快使用 ③ redirect_uri 必须与获取 code 时完全一致
返回 HTML 页面请求格式不对① 确认使用 GET 方式 ② 确认参数名 client_secret(非 client_key)

3.3 Step 3:获取用户信息#

此请求由应用后端发起。
请求方式: GET
GET {SSO地址}/oauth2.0/res?access_token={access_token}
参数说明:
参数必填类型说明
access_token✅string上一步获取的访问令牌,通过 URL 查询参数 传递
⚠️ 注意: access_token 必须通过 URL 查询参数传递,不支持 Authorization: Bearer <token> 请求头方式。
虽然原始文档中提到了 Bearer 头方式,但实际测试中 仅 URL 查询参数 能正确返回用户信息。
成功响应(HTTP 200):
{
    "code": 10000,
    "msg": "成功",
    "data": {
        "uid": "zhangsan",
        "name": "张三",
        "email": "zhangsan@example.com",
        "mobile": "+8613800138000"
    },
    "traceId": "0b4d7582-26eb-4edf-a192-1a247ee0a78e"
}
字段类型说明
codeint状态码,10000 表示成功
msgstring状态信息
data.uidstring用户唯一标识(登录账号名)
data.namestring用户真实姓名
data.emailstring用户邮箱地址
data.mobilestring用户手机号
traceIdstring请求追踪 ID,用于问题排查
返回的字段取决于 Step 1 中 scope 参数指定的范围。未授权的字段不会出现在响应中。

3.4 Step 4:完成本地登录#

获取到用户信息后,应用系统应执行本地登录逻辑:
1.
根据 uid 在本地数据库中查找对应用户
2.
如果用户存在 → 创建本地会话(Session / JWT / Cookie)
3.
如果用户不存在 → 自动创建本地账号,或返回"用户不存在"错误
4.
将浏览器重定向到应用首页或用户之前访问的页面

四、代码示例#

📌 代码说明
以下代码示例完整展示了 OAuth2.0 对接的核心逻辑,可直接用于开发参考。
Go 示例:完整可运行程序,直接 go run main.go 启动
Java 示例:展示 Spring Boot Controller 核心代码,需在已有 Spring Boot 项目中使用,补充对应依赖
Python 示例:完整可运行程序,pip install flask requests 后直接启动
所有示例中的 sso.example.com、client_id、client_secret 等配置需替换为实际值。
内网环境使用自签证书时,示例已包含跳过 TLS 校验的配置。

4.1 Java(Spring Boot)#

Spring Boot 配置文件 application.yaml:

4.2 Go#

4.3 Python(Flask)#


五、SSO 故障逃生机制#

⛔ 安全风险警告
启用逃生机制(降级到本地密码登录)意味着绕过了 SSO 的统一认证和多因素验证(MFA)。
这可能带来以下安全风险:
本地账号密码不受零信任策略保护(无 MFA、无设备检查、无地理围栏)
如果本地密码泄露,攻击者可直接登录,不会被 SSO 侧的异常检测拦截
审计日志中将缺少 SSO 登录事件,可能影响安全审计的完整性
使用建议:
1.
逃生机制仅限 SSO 完全不可用时的应急使用,恢复后应立即关闭
2.
本地管理员账号应设置高强度密码并定期轮换
3.
建议记录所有本地登录事件并设置告警,确保逃生期间的操作可审计
当 SSO 服务不可用时(网络故障、SSO 服务宕机等),应用系统需要有降级登录方案,否则所有用户都将无法访问系统。

5.1 设计思路#

用户访问 → 检查 SSO 状态 → SSO 可用?
                              ├── 是 → 正常 SSO 登录
                              └── 否 → 降级到本地账号密码登录

5.2 SSO 健康检查#

在显示登录页面之前,先探测 SSO 服务是否可用:
建议加缓存: 健康检查结果缓存 60 秒,避免每个用户请求都去探测 SSO:

5.3 前端降级逻辑#

5.4 管理后台手动关闭 SSO#

在管理后台提供一个"禁用 SSO"开关。当 SSO 故障时,管理员可以:
1.
通过管理后台关闭 SSO(设置 integration_configs.enabled = 0)
2.
或直接操作数据库:
3.
所有用户立即降级为本地账号密码登录
4.
SSO 恢复后,重新启用即可

5.5 保留管理员本地账号#

最佳实践: 无论是否启用了 SSO,始终保留至少一个 本地管理员账号(有密码),
确保在 SSO 完全不可用时,仍有人可以登录系统进行故障处理。

六、集成检查清单#

在上线前,逐项检查以下内容:

6.1 配置检查#

client_id 和 client_secret 已在管理后台获取
redirect_uri 与管理后台"应用回调地址"完全一致(包含协议、域名、路径)
scope 已正确设置(uid,name,email,mobile,逗号分隔)
后端可以通过 HTTPS 访问 SSO 服务地址(内网需配 DNS 或 hosts)

6.2 代码检查#

Token 接口使用 GET 方式(非 POST)
参数名使用 client_secret(非 client_key)
用户信息接口通过 URL 查询参数 传递 access_token
HTTP 客户端已配置 TLS 证书跳过(内网自签证书)
HTTP 客户端已禁用自动跟随 302 重定向(Go 特别注意)

6.3 安全检查#

client_secret 仅在后端使用,不暴露给前端/浏览器
state 参数已实现 CSRF 防护(存入 Cookie/Session,回调时校验)
授权码 code 仅使用一次,使用后立即废弃
SSO 故障逃生方案已实现并测试

6.4 测试验证#

正常 SSO 登录流程端到端通过
SSO 故障时可降级到本地登录
回调地址不匹配时有明确错误提示
日志中记录了完整的 SSO 事件(Token 请求、用户匹配、登录成功/失败)

七、常见问题(FAQ)#

Q1: Token 接口返回了 HTML 页面,不是 JSON?#

原因: 使用了 POST 方式,或参数名写成了 client_key。Token 接口只接受 GET 请求,参数名必须是 client_secret。

Q2: Token 接口返回 invalid_client?#

排查:
1.
确认 client_id 和 client_secret 值正确
2.
确认使用了 GET 方式(POST 也会导致此错误)
3.
确认参数名是 client_secret

Q3: Token 接口返回 invalid_grant?#

原因: 授权码 code 已失效。code 是一次性的,获取后需尽快使用(有效期较短),且不能重复使用。此外 redirect_uri 必须与获取 code 时完全一致。

Q4: Go 代码获取到 HTML 但 curl 返回 JSON?#

原因: Go 的 http.Client 默认自动跟随 302 重定向。SSO 服务可能返回 302 到登录页面,Go 自动跟随后获取到了 HTML。解决方法:

Q5: SSO 挂了怎么办?#

参见第五章"SSO 故障逃生机制"。核心思路:前端先检查 SSO 服务可用性,不可用则降级显示本地登录表单。同时始终保留一个有密码的本地管理员账号。

Q6: scope 参数中多个字段用什么分隔?#

用逗号分隔,如 uid,name,email,mobile。不是空格。

Q7: 用户在 SSO 上的账号名和本地系统的用户名不一致怎么办?#

建议在本地用户表中增加一个 sso_uid 字段,用于存储 SSO 返回的 uid。匹配策略:
1.
优先按 sso_uid 精确匹配
2.
未匹配时,按 username 匹配(如 MySQL utf8mb4_general_ci 不区分大小写)
3.
匹配成功后自动将 SSO uid 写入 sso_uid 字段,实现一次绑定

八、参考资源#

零信任平台 OpenSDK — 官方 Java Demo
零信任平台标准 Open API — 完整 API 文档

文档版本: v4.0 | 最后更新: 2026-03-11
修改于 2026-03-18 01:57:32
上一页
应用系统SSO对接
下一页
零信任平台Cas协议对接指南
Built with