对接方式总览
对接方式总览
Section titled “对接方式总览”业务系统接入 IAM 分成两个互相独立的对接面,可以只做其中一个:
| 对接面 | 解决的问题 | 协议 | 触发方向 |
|---|---|---|---|
| 统一身份登录(OIDC) | 用户是谁,怎么登录 | OAuth 2.1 / OIDC 授权码流程 | 应用 → IAM |
| 账户与访问权限同步 | 同步账户资料,开通或撤销应用访问 | 账户与访问权限同步协议(HMAC) | IAM → 应用 双向 |
只想让用户能统一登录,接入 OIDC 即可。需要同步账户资料、开通或撤销访问时,再接入账户与访问权限同步协议。是否自动建号由业务系统自己的规则决定。
1. 按系统选择文档
Section titled “1. 按系统选择文档”| 你的系统 | 阅读顺序 |
|---|---|
| CRM(Laravel + MySQL) | CRM 后端与 MySQL 接入 → 账户与访问权限同步协议 → CRM 账户同步本地验收 |
| OA(oacn-api + oain-web + MySQL) | OA 后端与 MySQL 接入(第 8 节为可选的账户与访问权限同步,接收端需自行实现) |
| 考试系统等第三方系统 | 考试系统 OIDC 接入 |
| 只想了解 IAM 侧配置 | OAuth Provider |
排障参考 OIDC 排障报告:签名上下文与 Cookie 链路的常见问题。
2. 对接前需要向 IAM 申请
Section titled “2. 对接前需要向 IAM 申请”由 IAM 负责人在管理端创建 OAuth Client,并通过安全渠道交付:
client_id、client_secret(机密客户端,只放后端,不进前端仓库);- issuer:生产为
https://iam.cq-i.cn/api/auth; - 登记好的 Redirect URI 与 Back-Channel Logout URI(必须逐字符一致)。
若接入账户与访问权限同步功能,还需要在「应用详情 → 访问控制 → 账户与访问权限同步」配置接收地址,并复制一次性生成的 Key ID 与 HMAC Secret 给接收系统。
3. 两条对接面的通用契约
Section titled “3. 两条对接面的通用契约”3.1 OIDC 侧
Section titled “3.1 OIDC 侧”- 端点一律从 Discovery(
/api/auth/.well-known/openid-configuration)读取,不要在代码里硬编码或猜测路径。 - 机密客户端使用
client_secret_basic,授权码流程强制 PKCE S256,且创建后不可关闭。 - ID Token 与 UserInfo 除标准 claim 外,额外透传
app_role、wecom_user_id、department_id。 - ID Token 使用 RS256(RSA 2048)签名,必须按
kid从 JWKS 验签,不能只解码 payload。 - 统一下线依赖 Back-Channel Logout:需要为 Client 配置
backchannel_logout_uri才能收到 Logout Token。
3.2 开通侧
Section titled “3.2 开通侧”- 事件与快照共用一套 HMAC-SHA256 签名头,规范串与测试向量见账户与访问权限同步协议。
- 接收方必须按
revision做单调性判断,否则迟到的旧事件会重新打开已撤销的访问。 - 投递最多 8 次、超时 15 秒,另有每 5 分钟一次的对账补发,接收方必须幂等。
- IAM 的
app_role只作参考,业务角色由应用自己的部门 / 职位规则映射,不使用 IAM 角色直接授权。
4. 常见对接失败原因
Section titled “4. 常见对接失败原因”| 现象 | 常见原因 |
|---|---|
| 授权被拒 / 回跳失败 | Redirect URI 与登记值不一致(协议、域名、端口、末尾 / 任一不同) |
| Token 请求 401 | 认证方式不是 client_secret_basic,或 PKCE verifier 与 challenge 不匹配 |
| 验签失败 | 使用了 Discovery 之外的算法,或未按 kid 命中 JWKS |
快照请求 403 CLIENT_MISMATCH |
用了 A 应用的凭据查询 B 应用的 clientId |
快照请求 409 REPLAY |
复用了已消费的 requestId,每次查询都要新生成 |
| 收到事件但权限没变 | 未按 revision 应用,或未处理 revoke 的 allowed: false |