AI应用接入 测试环境URL plaintext 生产环境URL plaintext 示例 wget 接口验签 对ai/portal/v1/app/queryUserInfoByTicket 请求接口URL进行参数验签 请求头需带 参数名 参数值类型 值描述 YLSignature YLTimestamp 毫秒时间戳 YLRandom 8位随机数,例如Cq8s9vqi YL3rdAppcode ak 管理员提供 第三方应用的签名生成由下面几项决定: URL参数params(目前只支持验签URL参数,body参数不验) 时间戳YLTimestamp 随机数YLRandom(由客户端随机生成,用于区分极短时间内发起的相同参数请求) 第三方应用标识码YL3rdAppcode 本地预埋的sk 签名YLSignature生成方法: 1.将请求参数键值对中的key按照字母升序排序,而后将排好序的参数以“&”为分隔符进行拼接,产生一个字符串; 2.在步骤1字符串的基础上,再按顺序将sk、YLTimestamp、YLRandom、YL3rdAppcode以“&”为分隔符拼接在末尾; 3.基于单向哈希算法SHA256,应用密钥sk对步骤2的字符串生成签名。 例如:SHA256(param1123¶m2456&sk×tamp&random&appcode) 参数 参数类型 参数说明 ak String 用于请求参数签名的ak 向服务方申请提供 sk String 用于请求参数签名的私钥,私发 Java签名算法例子 OpenApiUtil.txt plaintext package com.ctg.ai.platform.demo.util; import org.apache.commons.lang3.RandomStringUtils; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.; public class OpenApiUtil { private static final String KEYSEPARATOR "&"; / ak 由管理员提供 / private static final String HTTPHEADERYLAPPCODE "YL3rdAppcode"; / 时间戳 单位毫秒 / private static final String HTTPHEADERYLTIMESTAMP "YLTimestamp"; / 8位随机数 / private static final String HTTPHEADERYLRANDOM "YLRandom"; / 签名 / private static final String HTTPHEADERYLSIGNATURE "YLSignature"; / 组装验签头部 @param appKey @param appSecret @param paramMap @return / public static Map buildHeaders(String appKey, String appSecret, Map paramMap) { if (appKey null appSecret null) { return null; } // 组装前置条件 Long timestamp System.currentTimeMillis(); String random RandomStringUtils.randomAlphanumeric(8); // 计算签名 String signature buildSignature(appKey, appSecret, random, timestamp, paramMap); // 组装HTTP头部 return buildHeaders(appKey, random, timestamp, signature); } / 签名 @param appKey @param appSecret @param random @param timestamp @param paramMap @return / private static String buildSignature(String appKey, String appSecret, String random, Long timestamp, Map paramMap) { if (appKey null appSecret null random null timestamp null) { return null; } // 组成签名前原串 StringBuilder sb new StringBuilder(); if (paramMap ! null && paramMap.size() > 0) { List keys new ArrayList<>(paramMap.keySet()); // 参数排序 (ASCII 升序) Collections.sort(keys); for (String key : keys) { String val paramMap.get(key)[0]; sb.append(key).append("").append(val).append(KEYSEPARATOR); } } sb.append(appSecret).append(KEYSEPARATOR) .append(timestamp).append(KEYSEPARATOR) .append(random).append(KEYSEPARATOR) .append(appKey); ; return sha256(sb.toString().getBytes(StandardCharsets.UTF8)); } / 组装验签头部 @param appKey @param random @param timestamp @param signature @return / private static Map buildHeaders(String appKey, String random, Long timestamp, String signature) { Map headers new HashMap<>(4); if (appKey ! null) { headers.put(HTTPHEADERYLAPPCODE, appKey); } if (random ! null) { headers.put(HTTPHEADERYLRANDOM, random); } if (timestamp ! null) { headers.put(HTTPHEADERYLTIMESTAMP, ""+timestamp); } if (signature ! null) { headers.put(HTTPHEADERYLSIGNATURE, signature); } return headers; } // 哈希部分逻辑 private static final char[] LOWERHEXDIGITS new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static final String MD5ALGORITHMNAME "MD5"; private static final String SHA256ALGORITHMNAME "SHA256"; public static String md5(byte[] data) { return encodeAsHexString(MD5ALGORITHMNAME, data); } public static String sha256(byte[] data) { return encodeAsHexString(SHA256ALGORITHMNAME, data); } / 使用 {@code algorithmName} 加密算法编码 {@code data} @param algorithmName 算法名 @param data 被编码的字节数组 @return {@code data} 编码后的小写 16 进制形式字符串 @throw IllegalStateException 当找不到 {@code algorithmName} 对应算法 / private static String encodeAsHexString(String algorithmName, byte[] data) { try { byte[] hash MessageDigest.getInstance(algorithmName).digest(data); return new String(encodeHex(hash)); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("MessageDigest 找不到算法:" + algorithmName, e); } } private static char[] encodeHex(byte[] data) { int l data.length; char[] arr new char[l >> 4]; arr[j++] LOWERHEXDIGITS[15 & data[i]]; } return arr; } public static void main(String[] args) { String ak "ak"; String sk "sk"; Map paramMap new HashMap<>(2); paramMap.put("param2", new String[]{"456","789"}); paramMap.put("param1", new String[]{"123"}); Map header buildHeaders(ak, sk, paramMap); System.out.println("header"+header); } }