联调验收与排障
先确认环境
- 平台是否部署了包含本公开文档的版本;公开
/docs不需要管理员登录。 - 发现文档 issuer 是否与产品配置完全一致;不要混用
sso.too1.net与platform.too1.net。 - Client 类型是否正确,回调是否精确登记,产品和 Client 是否启用。
- 短信/支付 API 是否使用独立服务 Token,并具备相应 Scope、模板授权与产品商户绑定。
- 服务器时间、HTTPS、DNS 和出口 IP/CIDR 白名单是否正确;不要关闭 TLS 校验来“修复”网络错误。
错误分类
OIDC Token 错误为 {"error":"invalid_client","error_description":"..."}。平台业务 API 错误为 {"error":{"code":"...","message":"...","request_id":"..."}}。不能用同一 JSON 字段类型直接解析两者。
| 场景 / 错误 | 重点检查 | 恢复方式 |
|---|---|---|
OIDC invalid_client |
Client ID、类型、Basic 密钥、启用状态 | 修正配置,Native 不发 Secret |
OIDC invalid_request |
state/nonce/PKCE、回调、scope | 重新生成登录事务,不删安全参数 |
OIDC invalid_grant |
授权码过期/重放、verifier、不匹配的回调、刷新重放 | 重新登录,禁止循环重放旧 Token |
login_required |
无中央会话却要求静默登录 | 由用户发起交互式登录 |
invalid_token |
服务令牌过期、用户令牌误用、Client 禁用 | 检查类型,再按策略重新获取服务 Token |
insufficient_scope |
Scope 或来源 IP 限制 | 管理员最小权限授权,不扩大到所有 Scope |
template_not_granted |
模板授权/状态 | 后台登记并授权该产品 |
quota_exceeded / rate_limited |
产品/手机号/模板额度与频率 | 等待窗口;不循环换 Key 绕限流 |
idempotency_conflict |
同一个 Key 的原始请求字节不同 | 找回原请求,新的业务操作才用新 Key |
idempotency_in_progress |
同 Key 请求仍在处理 | 等待并查询已知资源,不能当失败重新下单 |
return_url_not_allowed |
返回 URL 与白名单不完全一致 | 登记实际地址,不传任意前端参数 |
duplicate_external_order |
同产品订单已创建 | 使用保存的 payment_id 查询;无 ID 则运维核查 |
duplicate_external_refund |
同业务退款号已申请 | 查询原退款,不能再次申请同一退款 |
channel_result_unknown |
渠道未确认操作结果 | 保持处理中并查询,不把 202 当成功 |
storage_error / idempotency_storage_error |
操作可能已到渠道但本地结果保存失败 | 保留原 Key/业务单号,查询或人工核查,禁止盲目重发 |
sms_disabled / payments_disabled |
渠道、产品或事故开关 | 联系管理员;不要自动开启 |
平台的查询接口按产品隔离;其他产品的资源或不存在资源可能均返回 404,不要用这种差异枚举记录。
登录两次就限流、退出后立即又登录
先看失败请求的域名、路径和响应格式,区分产品网关与平台认证接口。产品返回的 {"success":false,"error":{"code":"RATE_LIMITED"}} 不是平台业务 API 的响应结构;不能仅凭“请求过于频繁”就断定平台密码失败计数达到阈值。
产品接入方应检查以下链路:
- 登录入口、OIDC 回调、会话探测、退出是否共用同一个 IP 限流桶;计数可能是 HTTP 请求次数而非输错密码次数。
- 浏览器
OPTIONS是否被错误计入认证桶,429 是否带Retry-After和合法 Origin 的 CORS 响应头。 - 反向代理是否传递真实 IP,以及后端是否仅信任实际代理的精确 CIDR。若所有用户被识别为同一个代理 IP,会共同消耗限额。不要开启全网可信代理。
/me的 429/5xx 是否被当成未登录后自动跳转,以及登录失败页、退出结果页是否又自动启动 SSO。退出后保留中央会话是正常范围选择;自动登录循环不是。- 产品自己的 Session 是否确实在服务端撤销,不能仅删除前端缓存或旧 localStorage 项。
平台 /logout 的 GET 现在只显示确认页,POST 要求 CSRF。OIDC 产品请使用发现文档中的登出端点及登记的回跳地址。数据库故障时平台保留可重试 Cookie、返回错误及请求编号,不显示成功;重试成功后原 Cookie 必须无法再访问账号中心。不要把错误页或网络超时当成已经退出,也不要把回跳网页显示成功当成所有产品的业务会话都已撤销。
记录哪些排障信息
保留时间、平台请求编号 X-Request-ID / error.request_id、接口路由模板、HTTP 状态、安全错误码、产品内部操作编号、耗时。管理员凭请求编号在“系统日志”检索。
不要贴完整 Authorization、密码、短信验证码、Cookie、Refresh Token、一次性凭据或带收银台令牌的完整 URL。接口错误发生时,记录“创建支付失败”及安全编号即可,不输出全部 HTTP request/response。
公开文档不显示环境内部状态、管理员会话或实际配置。系统日志、渠道验证状态、审计和凭据仍只在受保护后台查看。
最小自动化验收矩阵
| 模块 | 必测成功 | 必测失败 |
|---|---|---|
| Web OIDC | 首次认证、既有会话、原业务用户映射 | 错误 state/nonce/PKCE、错误 issuer/audience、过期签名、码重放 |
| Native | 回调接收、取消、超时、刷新保存 | Scheme 不符、跨事务、端口冲突、并发刷新 |
| Service | Token 获取、Scope 子集、到期更新 | 用户 Token 冒用、Native 密钥、禁用/IP 限制 |
| SMS | 授权模板、受理、查询 | 非 +86、额外参数、额度、未知结果、幂等冲突 |
| 支付 | 创建、查询、回调、权益 | 前端改金额、越权、重复下单、伪造返回成功 |
| 退款 | 部分/全额、审批后处理 | 超额、重复、并发、未知结果 |
| Webhook | 验签、可靠入库、幂等权益 | 伪造/超窗、重复/乱序、数据库失败和重启 |
| 迁移 | 正确映射、续跑、首登协议 | 空/重复手机号、外部 ID 冲突、无映射误建新号 |
平台提供的验收命令
./ssoctl doctor
./ssoctl audit verify
./ssoctl oidc smoke web --issuer https://platform.too1.net --client-id smoke-web --secret-file smoke-web.secret
./ssoctl oidc smoke native --issuer https://platform.too1.net --client-id smoke-native
./ssoctl platform payment simulate --channel wechat
./ssoctl platform payment simulate --channel alipay
doctor/audit 由持有平台运维配置的人运行。OIDC smoke 用独立测试 Client;模拟支付不等于真实 HTTP/数据库或商户验收。真实短信发送、真实支付/退款不能在 CI 中默认执行。
正式切换门禁
先升级 staging 并完成真实产品回调。至少完成一条真实联麓短信、公众号未关注/已关注扫码,微信和支付宝各 0.01 元支付、查询、回调、退款;未完成的渠道保持关闭。完成迁移对账、恢复演练、目标服务器容量测试和独立随机密钥检查,再逐步放量。
单元测试通过、文档公开或看到“登录成功”页面,都不能替代产品侧映射和本地会话验收。真实交易产生后回滚不能停掉回调/查询 Worker,更不能直接恢复不认识新交易数据的旧二进制。