一、集成平台是什么?(小白秒懂版)
1.1 简介
想象一下:医院里有挂号处、诊室、药房三个地方。
传统方式:你要先去挂号处拿号 → 自己找诊室 → 自己找药房(容易迷路)
集成平台方式:你只告诉前台(集成平台)需求 → 前台带你去每个地方(安全又省心)
- "应用集成平台充当认证中心和授权中心,协助系统间安全传递业务参数。"
- 应用集成平台只做"桥梁",不替代各系统自己的功能!
一句话总结:集成平台 = 系统间的"前台服务员",帮你安全地从A系统走到B系统!
1.2 安全机制
Token认证 :所有接口调用都需要有效的Token
SM4加密 :数据传输使用SM4加密保护
防重复请求 :使用Redisson分布式锁防止重复请求
黑名单验证 :系统/IP级别的黑名单验证
参数验证 :严格的参数格式和有效性验证
1.3 技术实现关键点
Redis缓存 :Token(5小时)、Ticket(300秒)、会话ID等缓存
Kafka消息 :使用主题 IAP_TOPIC_${servCode} 进行消息广播
分布式锁 :Redisson锁防止重复请求
事务管理 :@Transactional注解确保数据一致性
异常处理 :统一的异常处理机制
二、集成平台能做什么?(三大场景)
| 场景 | 适用情况 | 例子 | 需要哪些接口 |
|---|---|---|---|
| 1. 页面重定向 | 需要浏览器跳转到另一个系统页面 | 从挂号系统跳转到互联网医院问诊页 | 申请Token + 申请授权码(A系统地址重定向) + 认证授权(B系统校验授权码) |
| 2. HTTP API调用 | 需要后台获取数据(用户无感) | 互联网医院调用挂号系统的科室列表 | 申请Token + 服务调用 |
| 3. 消息广播 | 需要通知多个系统同一件事 | 挂号系统发布"新号源",通知所有相关系统 | 申请Token + 发布消息 + 确认消息 |
✅记住这个判断法:
有页面跳转? → 用场景1
需要后台取数据? → 用场景2
要群发通知? → 用场景3绝不混用!
2.1 核心组件
IapRuntimeController.java :核心运行时控制器,处理所有接口请求
服务层 :实现业务逻辑(订阅验证、token管理等)
数据访问层 :使用MyBatis-Plus操作数据库
缓存层 :Redis用于token、ticket等缓存
消息队列 :Kafka用于消息广播
2.2 主要接口
| 接口地址 | 功能描述 | 请求方法 |
|---|---|---|
/interface/v1/token | 申请访问令牌 | POST |
/interface/v1/preauth | 页面重定向预授权(申请授权码) | POST |
/interface/v1/authentication | 页面重定向认证(认证授权) | POST |
/runtime/v1/** | 服务调用 | POST |
/interface/v1/publish/message | 消息广播发布 | POST |
三、前期准备:必须知道的基础知识
3.1 系统编码表— 每个系统都有"身份证号"
| 系统名称 | 编码 | 你的身份 |
|---|---|---|
| 挂号平台 | 100 | 如果你是挂号系统,记下100 |
| 互联网医院 | 101 | 如果你是互联网医院,记下101 |
| 百度灵医 | 901 | 常见能力系统 |
| 支付宝 | 902 | 常见能力系统 |
| 集成平台 | 999 | 所有请求都要知道它 |
| 护理平台 | 102 | 其他业务系统 |
📌重要:每次调用接口,请求头必须携带你的系统编码!
3.2 通信规则
所有数据都加密:使用SM4加密算法(像给信件加密码锁)
请求格式:
{ "param": "加密后的业务数据" }响应格式:
{ "code": "200", "message": "成功", "data": "加密后的返回数据" }
3.3安全要求
每个请求必须做到:
在请求头写入
systemCode(你的系统编码)生成24位唯一
messageId(不能重复!)在加密的param中再次写入相同的messageId
除Token接口外,其他接口必须携带
token参数
四、三大场景详细操作指南(带示例)
场景1:页面重定向(从A系统跳到B系统)
典型业务:挂号系统(100) → 跳转到 互联网医院(101)
必须接口:`/iap/interface/token` + `/iap/interface/v1/preauth` + `/iap/interface/v1/authentication`
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 系统B │ │ IAP平台 │ │ 系统A │ └─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ │ 1. 申请Token │ │ │───────────────────>│ │ │ │ │ │ 2. 返回Token │ │ │<───────────────────│ │ │ │ │ │ 3. 预授权请求 │ │ │───────────────────>│ │ │ │ 4. 验证Token │ │ │───────────────────>│ │ │ │ │ │ 5. 生成Ticket和Session│ │ │───────────────────>│ │ │ │ │ 6. 返回重定向URL │ │ │<───────────────────│ │ │ │ │ │ 7. 重定向到系统A │ │ │────────────────────────────────────────>│ │ │ │ │ │ 8. 验证Ticket │ │ │<───────────────────│ │ │ │ │ │ 9. 返回Session参数 │ │ │───────────────────>│ ┌─────┴───────┐ ┌─────┴───────┐ ┌─────┴───────┐ │ 系统B │ │ IAP平台 │ │ 系统A │ └─────────────┘ └─────────────┘ └─────────────┘1. 申请Token :系统B调用 /interface/v1/token 接口获取Token 2. 预授权 :系统B调用 /interface/v1/preauth 接口,提供servCode等参数 3. 生成Ticket :IAP生成16位ticket,有效期300秒,存储在Redis中 4. 保存Session :IAP保存会话信息到 iap_session 表,参数到 iap_session_serv_param 表 5. 返回重定向URL :IAP返回包含sessionId、ticket和redirectUri的响应 6. 重定向 :系统B重定向到系统A的页面 7. 验证Ticket :系统A调用IAP的 /interface/v1/authentication 接口验证ticket 8. 返回Session参数 :IAP返回会话参数给系统A
步骤1:A系统(挂号系统)获取Token
接口:
POST /iap/interface/token请求头:
systemCode: 100 messageId: 1719225600100099903011234(24位唯一ID)请求体(加密后):
{ "clientId": "system_100", "clientSecret": "你的密钥" }返回(解密后):
{ "token": "Token_100_abc123", "sessionId": "session_123" }
步骤2:A系统申请跳转凭证(关键步骤!)
接口:
POST /iap/interface/v1/preauth请求头:
systemCode: 100 messageId: 1719225600100099903025678(新ID) token: Token_100_abc123(上一步获得)请求体(加密后):
{ "messageId": "1719225600100099903025678", "servCode": "online_hospital", "param": { "user": { "systemUserId": "123", "systemUserName": "张三" } } }返回(解密后):
{ "redirectUrl": "http://hospital.com/chat", "ticket": "ticket_xyz789", "timestamp": "1719225600", "sessionId": "preauth_456" }
步骤3:A系统跳转到B系统
操作:浏览器重定向到
http://hospital.com/chat?ticket=ticket_xyz789×tamp=1719225600&presessionid=preauth_456
步骤4:B系统(互联网医院)验证跳转
接口:
POST /iap/interface/v1/authentication请求头:
systemCode: 101 messageId: 1719225600101099903039012(新ID) token: Token_101_def456(B系统自己的Token)请求体:请求集成平台验证ticket是否有效
{ "ticket": "ticket_xyz789", "timestamp": "1719225600" }返回:用户信息等业务参数
✅场景1完整流程: A系统拿Token → A系统申请跳转凭证 → 浏览器跳转 → B系统验证凭证 → 进入业务页面
场景2:HTTP API调用(后台获取数据)
典型业务:互联网医院(101)调用挂号系统(100)的科室列表
必须接口:/iap/interface/token+/iap/runtime/v1/{uri}
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 系统B │ │ IAP平台 │ │ 系统A │ └─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ │ 1. 申请Token │ │ │───────────────────>│ │ │ │ │ │ 2. 返回Token │ │ │<───────────────────│ │ │ │ │ │ 3. 调用服务(带Token)│ │ │───────────────────>│ │ │ │ 4. 验证Token │ │ │───────────────────>│ │ │ │ │ │ 5. 验证订阅关系 │ │ │───────────────────>│ │ │ │ │ │ 6. 转发请求 │ │ │───────────────────>│ │ │ │ │ │ 7. 返回响应 │ │ │<───────────────────│ │ │ │ │ 8. 返回加密响应 │ │ │<───────────────────│ │ ┌─────┴───────┐ ┌─────┴───────┐ ┌─────┴───────┐ │ 系统B │ │ IAP平台 │ │ 系统A │ └─────────────┘ └─────────────┘ └─────────────┘服务发布(系统A)
在 iap_serv 表配置服务(状态=ENABLE)
在 iap_serv_http_api 表配置API信息(请求URI、方法等)
服务订阅(系统B订阅系统A对应的服务)
调用 IapServSubscribeController.create() 接口
保存订阅关系到 iap_serv_subscribe 表
描述:
1. 申请Token :系统B调用 /interface/v1/token 接口,获取有效期为5小时的Token
2. 调用服务 :系统B使用Token和加密参数调用 /runtime/v1/** 接口
3. 验证Token :IAP验证Token的有效性和系统匹配性
4. 验证订阅关系 :IAP检查系统B是否已订阅该服务
5. 转发请求 :IAP将请求转发给系统A
6. 返回响应 :系统A返回响应,IAP加密后返回给系统B
步骤1:B系统(互联网医院)获取Token
接口:
POST /iap/interface/token请求头:
systemCode: 101 messageId: 1719225600101099903043456(24位ID)请求体(加密后):
{ "clientId": "system_101", "clientSecret": "你的密钥" }返回:
{ "token": "Token_101_def456", "sessionId": "session_789" }
步骤2:B系统调用服务
接口:
POST /iap/runtime/v1/departments请求头:
systemCode: 101 messageId: 1719225600101099903057890(新ID) token: Token_101_def456(上一步获得)请求体(加密后):
{ "messageId": "1719225600101099903057890", "serviceCode": "get_departments", "param": { "hospitalId": "123456" } }返回(解密后):
{ "departments": [ {"id": "1", "name": "内科"}, {"id": "2", "name": "外科"} ] }
✅场景2完整流程: B系统拿Token → B系统直接调用服务 → 获取数据
注意:此场景不调用
/iap/interface/v1/preauth(申请授权码)和/iap/interface/v1/authentication(认证授权)
场景3:消息广播(群发通知)
典型业务:挂号系统(100)发布"新号源",通知所有订阅系统
必须接口:/iap/interface/token+/iap/interface/v1/publish/message+/iap/interface/v1/commit/message
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 系统A │ │ IAP平台 │ │ Kafka │ └─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ │ 1. 申请Token │ │ │───────────────────>│ │ │ │ │ │ 2. 返回Token │ │ │<───────────────────│ │ │ │ │ │ 3. 发布消息请求 │ │ │───────────────────>│ │ │ │ 4. 验证Token │ │ │───────────────────>│ │ │ │ │ │ 5. 验证发布权限 │ │ │───────────────────>│ │ │ │ │ │ 6. 发布Kafka消息 │ │ │───────────────────>│ │ │ │ │ 7. 返回发布结果 │ │ │<───────────────────│ │ ┌─────┴───────┐ ┌─────┴───────┐ ┌─────┴───────┐ │ 系统A │ │ IAP平台 │ │ Kafka │ └─────────────┘ └─────────────┘ └─────────────┘描述:
1. 申请Token :系统A调用 /interface/v1/token 接口获取Token
2. 发布消息 :系统A调用 /interface/v1/publish/message 接口,提供topicName和消息内容
3. 验证Token :IAP验证Token的有效性
4. 验证发布权限 :IAP检查系统A是否有权发布该服务的消息
5. 发布Kafka消息 :IAP将消息发布到 IAP_TOPIC_${servCode} 主题
6. 返回结果 :IAP返回发布结果给系统A
步骤1:发布方(挂号系统)获取Token
接口:
POST /iap/interface/token请求头:
systemCode: 100 messageId: 1719225600100099903061234
步骤2:发布方发布消息
接口:
POST /iap/interface/v1/publish/message请求头:
systemCode: 100 messageId: 1719225600100099903075678 token: Token_100_abc123请求体(加密后):
{ "topicName": "new_appointment", "param": { "department": "内科", "date": "2023-07-25" } }
步骤3:订阅方处理消息
操作:订阅方(如互联网医院)从Kafka消费消息
"各订阅方,凭管理员提供的TOPIC和GROUP,订阅和消费消息。"
步骤4:订阅方确认消息
接口:
POST /iap/interface/v1/commit/message请求头:
systemCode: 101 messageId: 1719225600101099903089012 token: Token_101_def456 presessionid: session_from_kafka请求体(加密后):
{ "publishMsgId": "消息ID_abc123", "ack": "1" // 1=成功,0=失败 }
✅场景3完整流程: 发布方拿Token → 发布方发布消息 → 订阅方消费消息 → 订阅方确认消息
注意:此场景不调用
/iap/interface/v1/preauth(申请授权码)和/iap/interface/v1/authentication(认证授权)
五、常见错误与解决方案
| 错误码 | 错误信息 | 原因 | 解决方案 |
|---|---|---|---|
| 1000 | 请勿重新调用 | messageId重复 | 每次请求生成新24位ID |
| 1001 | 参数缺失 | 缺少必填参数 | 检查文档要求的参数是否都传了 |
| 1003 | 票根无效 | 用了错误的ticket | 重新调用/iap/interface/v1/preauth获取新ticket |
| 1004 | 票根重复消费 | 同一个ticket用了两次 | 每次跳转必须用新ticket |
| 1004 | 票根过期 | ticket超过100秒 | 生成后100秒内必须使用 |
| 1005 | 令牌无效 | Token过期或错误 | 重新调用/iap/interface/token |
| 1006 | 服务未授权 | 没订阅这个服务 | 先在管理平台订阅服务 |
| 1009 | 服务不存在 | 服务未上架 | 联系管理员上架服务 |
🚨最高频错误:
messageId重复(1000):集成平台不做幂等,必须每次生成新ID!
Token过期(1005):Token有效期通常30分钟,过期必须重申请!
票根过期(1004):ticket100秒内必须用,否则重申请!
六、重要安全提醒(必须遵守!)
1. Token使用规则
Token是临时凭证,每次调用服务前都要验证是否有效
绝对不能把Token写死在代码里,每次用前检查有效期
Token泄露 = 身份被盗用,必须严格保密
2. 数据加密要求
所有业务参数必须SM4加密,不能传明文
加密示例(Java):
SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(secretKey)); String encrypted = sm4.encryptHex(plaintext);
3. 请求唯一性
messageId生成规则:0-12位: 13位时间戳13-16位: 四位系统编码(不足左补0,如0100)17-20位: 接口目录编码(如0301)21-24位: 4位随机数示例:
1719225600100010003019876
4. 场景区分
页面跳转→ 用3.1+3.2接口
后台取数据→ 用3.4接口
群发通知→ 用3.5+3.7接口
七、快速自查清单(调用前必看)
✅通用检查:
请求头写了正确的
systemCode(100/101/901...)生成了24位唯一
messageId在加密的param中重复写入相同的
messageId除Token接口外,其他接口都带了
token参数
✅场景1(页面跳转)检查:
A系统已调
/iap/interface/tokenA系统已调
/iap/interface/v1/preauth(带token!)重定向URL包含
ticket+timestamp+presessionidB系统已调
/iap/interface/v1/authentication验证
✅场景2(API调用)检查:
B系统已调
/iap/interface/token调用的是
/iap/runtime/v1/{uri},不是3.1/3.2接口请求体包含
serviceCode和业务参数
✅场景3(消息广播)检查:
发布方已调
/iap/interface/token调用
/iap/interface/v1/publish/message时指定了topicName订阅方从Kafka消费后,已调
/iap/interface/v1/commit/message确认
八、总结
IAP集成平台通过统一的入口、严格的安全认证和高效的消息传递机制,实现了不同系统之间的安全、高效通信。
系统间的所有交互都通过IAP进行转发和验证,大大降低了系统间直接连接的复杂度和安全风险。
最后提醒:集成平台是工具,核心业务逻辑仍在各系统自身。
附录:关键接口速查表
| 场景 | 接口URL | 用途 | 必填参数 |
|---|---|---|---|
| 通用 | /iap/interface/token | 申请Token | clientId, clientSecret |
| 页面跳转 | /iap/interface/v1/preauth | 申请跳转凭证 | token, servCode |
| 页面跳转 | /iap/interface/v1/authentication | 验证跳转 | token, ticket, timestamp |
| API调用 | /iap/runtime/v1/{uri} | 调用服务 | token, serviceCode |
| 消息广播 | /iap/interface/v1/publish/message | 发布消息 | token, topicName |
| 消息广播 | /iap/interface/v1/commit/message | 确认消息 | token, publishMsgId, ack |