第三方系统集成助手
约 1046 字大约 3 分钟
2025-04-16
第三方系统集成中交人工智能服务助手
概述
中交人工智能服务助手支持第三方系统集成 ,第三方系统可以嵌入 中交人工智能服务助手页面实现业务集成
中交人工智能服务助手 向第三方系统提供 通过外部用户 id 获取鉴权token 信息接口,用于集成时的调用其他数据接口时使用。
说明
- 签名使用 HMAC(哈希消息认证码) 对称加密生成 sign,第三方系统使用密钥加密产生签名,中交人工智能服务助手使用对应密钥解密签名再比对
- 如果外部用户 id(uid)是 4A 的账号,将关联中交人工智能服务助手内的 4A 账号
相关接口
1. 根据第三方助手用户 id 获取鉴权信息
- 请求方式:POST(HTTPS)
- 请求地址:https://c4ai.ccccltd.cn/api/sys-auth/oauth/openid/token
- 请求包体(body):
{
"source": "cde",
"uid": "qunz",
"ts": "1733910570",
"sign": "DsCKM9yiMDsbNTVr56XxBYBB8co="
}- 参数说明 相关参数 sign、source 联系基础研发部获得
| 参数 | 是否必填 | 说明 |
|---|---|---|
| uid | 是 | 第三方系统账号 id,用户账号的唯一标识,可以为 4A 账号 |
| ts | 是 | timestamp,当前时间戳,单位为秒级 |
| ttl | 否 | Time to Live,时间戳的有效期,默认 180 秒,单位为秒级 |
| sign | 是 | 参数加密后的签名 |
| source | 是 | 第三方系统来源标识 |
返回结果:
{
"status": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImZ1c2lvbiIsInVzZXJfbmFtZSI6Il90ZXN0Iiwic2V4IjpudWxsLCJ1c2VyTm8iOm51bGwsInVzZXJOYW1lIjoiX3Rlc3QiLCJjbGllbnRfaWQiOiJmdXNpb24iLCJhdmF0YXJUb2tlbiI6bnVsbCwibGljZW5zZSI6InBvd2VyZWQgYnkgZnVzaW9uIiwiYXVkIjpbIm9hdXRoMi1yZXNvdXJjZSIsIm9hdXRoMi1zZXJ2ZXIiXSwicGhvbmUiOm51bGwsInNjb3BlIjpbImFsbCJdLCJ0ZW5hbnRJZCI6MTAwMDAwLCJ1c2VyRnVsbG5hbWUiOm51bGwsImlkIjoiMTg2NjczMzY1MjEzNzY4NDk5MyIsInVzZXJUeXBlIjoyLCJleHAiOjE3MzY0OTA5NjAsImp0aSI6ImE1NGEyMjIxLWRiMWItNGIzMy1hNGMzLTU1N2E4MjE5NDM3MCIsImVtYWlsIjpudWxsfQ.XK2rg9N3BrgNwcvtzndiwiE2vHPJHjvqrwg-XNg_sU4",
"expires_in": "2591999"
},
"code": 8000000,
"message": "成功",
"txId": "null"
}签名的加密过程
- 获取系统当前时刻时间戳
- 将除了 sign 之外的参数,分别拼接成 "k=v" 形式的字符串
- 将拼接后的字符串,进行自然排序,再用 "&" 串联,得到参数明文字符串
- 对参数明文字符串使用密钥进行加密,得到 sign 的值 xxx
- 最后在请求 body 中添加上 sign=xxx 参数,请求接口获取数据
签名的校验过程
- 校验参数是否缺失
- 校验第三方助手来源标识(source)是否正确
- 生成当前时间戳,校验参数中的时间戳(ts)是否超时,默认 3 分钟内有效,可以传参 ttl 控制签名的有效期
- 根据对应的第三方助手密钥生成签名,与参数中签名(sign)进行比对,校验签名的正确性
签名计算代码样例
/**
* 生成签名
*/
public static String calculateRFC2104HMAC(String data, String secretKey) throws SignatureException {
try {
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
return new String(Base64.getEncoder().encode(rawHmac), StandardCharsets.UTF_8);
} catch (Exception var6) {
throw new SignatureException("Failed to generate HMAC : " + var6.getMessage());
}
}
/**
* 参数排序
*/
public static String buildSortParam(Map<String, String> singleValueMap) {
List<String> paramList = new ArrayList<>(singleValueMap.size());
singleValueMap.forEach((k, v) -> {
if (!Objects.equals("sign", k)) {
String param = k + "=" + v;
paramList.add(param);
}
});
Collections.sort(paramList);
return StringUtils.collectionToDelimitedString(paramList, "&");
}- python版本的代码样例
import requests
import hmac
import hashlib
import base64
import time
def calculate_signature(secret_key, params):
# 排除sign参数
filtered_params = {k: v for k, v in params.items() if k != 'sign'}
# 拼接成 "k=v" 形式的字符串
param_strings = [f"{k}={v}" for k, v in filtered_params.items()]
# 自然排序
param_strings.sort()
# 用 "&" 串联
data_to_sign = "&".join(param_strings)
# 使用密钥进行加密
h = hmac.new(secret_key.encode('utf-8'), data_to_sign.encode('utf-8'), hashlib.sha1)
signature = base64.b64encode(h.digest()).decode('utf-8')
return signature
def get_token(secret_key, source, uid, ttl=180):
ts = str(int(time.time()))
params = {
"source": source,
"uid": uid,
"ts": ts,
"ttl": ttl
}
sign = calculate_signature(secret_key, params)
params["sign"] = sign
# 重要:需要增加User-Agent的header,不然会被安全识别为脚本攻击
headers = {
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
url = "https://c4ai.ccccltd.cn/api/sys-auth/oauth/openid/token"
response = requests.post(url, json=params, headers=headers)
if response.status_code == 200:
result = response.json()
if result["status"]:
return result["data"]["access_token"]
else:
print(f"获取token失败,错误信息: {result['message']}")
else:
print(f"请求失败,状态码: {response.status_code}")
# 请替换为实际的密钥和source
secret_key = "${your_secret_key}"
source = "${your_source}"
uid = "${your_uid}"
token = get_token(secret_key, source, uid)
if token:
print(f"获取到的token: {token}")Iframe 嵌入基础方式,最快效果,不需要 SDK
<iframe id="aichat"></iframe>
<script>
const dom = document.getElementById("aichat");
// path: 请联系基础基础研发部获得, token根据接口文档获得,token所需要
dom.src = `https://${path}?token=${token}`;
</script>