Skip to content

第三方系统集成助手

约 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 账号
tstimestamp,当前时间戳,单位为秒级
ttlTime to Live,时间戳的有效期,默认 180 秒,单位为秒级
sign参数加密后的签名
source第三方系统来源标识

返回结果:

{
  "status": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImZ1c2lvbiIsInVzZXJfbmFtZSI6Il90ZXN0Iiwic2V4IjpudWxsLCJ1c2VyTm8iOm51bGwsInVzZXJOYW1lIjoiX3Rlc3QiLCJjbGllbnRfaWQiOiJmdXNpb24iLCJhdmF0YXJUb2tlbiI6bnVsbCwibGljZW5zZSI6InBvd2VyZWQgYnkgZnVzaW9uIiwiYXVkIjpbIm9hdXRoMi1yZXNvdXJjZSIsIm9hdXRoMi1zZXJ2ZXIiXSwicGhvbmUiOm51bGwsInNjb3BlIjpbImFsbCJdLCJ0ZW5hbnRJZCI6MTAwMDAwLCJ1c2VyRnVsbG5hbWUiOm51bGwsImlkIjoiMTg2NjczMzY1MjEzNzY4NDk5MyIsInVzZXJUeXBlIjoyLCJleHAiOjE3MzY0OTA5NjAsImp0aSI6ImE1NGEyMjIxLWRiMWItNGIzMy1hNGMzLTU1N2E4MjE5NDM3MCIsImVtYWlsIjpudWxsfQ.XK2rg9N3BrgNwcvtzndiwiE2vHPJHjvqrwg-XNg_sU4",
    "expires_in": "2591999"
  },
  "code": 8000000,
  "message": "成功",
  "txId": "null"
}
  • 签名的加密过程

    1. 获取系统当前时刻时间戳
    2. 将除了 sign 之外的参数,分别拼接成 "k=v" 形式的字符串
    3. 将拼接后的字符串,进行自然排序,再用 "&" 串联,得到参数明文字符串
    4. 对参数明文字符串使用密钥进行加密,得到 sign 的值 xxx
    5. 最后在请求 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>

Iframe 嵌入基础方式,最快效果,不需要 SDK