接口签名文档
1、应用接口"授权"配置 (应用管理)
2、生成签名"凭证"
签名生成流程
参数排序与拼接:将请求参数(除secret外)按字母升序排列,拼接为
key1=value1&key2=value2
格式的字符串密钥混合:在字符串尾部拼接
secretKey
参数值(如paramStr + secretKey
)14。加密处理:使用MD5或SHA-1算法生成32位大写签名(如
DigestUtils.md5Hex
)15。
验证机制
服务端通过相同规则生成签名,比对客户端传入的sign
值,若不一致则拒绝请求
需注意时间戳(timestamp
)防重放攻击,通常设置5分钟有效期
3、php示例
class ycyl { const secretKey = '你的secretKey';//开发授权配置中获取 public static function generate(array $params): string { unset($params['sign']); $params = array_filter($params); ksort($params); $queryString = ''; foreach ($params as $k => $v) { $queryString .= "{$k}={$v}&"; } $signString = rtrim($queryString, '&') . self::secretKey; //加密方式(md5或sha1)与配置对应 return md5($signString); } //发送请求 static function getData($url, $data) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return $response; } } // 测试用例 $params = [ 'appId' => '82630636260712508048888', 'timestamp' => time(), 'nonce' => bin2hex(random_bytes(4)) //接口业务参数(查看接口) //... ]; $sign = SignGenerator::generate($params); $params['sign'] = $sign; $url = '';//接口地址 $res = ycyl::getData($url, $params);//请求接口数据 //检验返回的结果(防止传输被篡改) $resArray = json_decode($res, true); if ($resArray['code'] != 0) { die($resArray['msg']); } if ($resArray['sign'] == ycyl::generate($resArray)) { //处理数据 $resdata = json_decode($resArray['data'], true);//字符串转数组 var_dump($resdata); } else { die('校验失败'); }
4、其他语言核心代码
a、Node签名
const crypto = require('crypto');
class SignGenerator {
static generate(params) {
const SECRET_KEY = 'your_secret_key_here';
// 1. 移除sign字段并过滤空值
const filtered = {};
Object.keys(params).forEach(key => {
if (key !== 'sign' && params[key] != null) {
filtered[key] = params[key];
}
});
// 2. 参数按字母顺序排序
const sortedKeys = Object.keys(filtered).sort();
let queryString = '';
sortedKeys.forEach(key => {
queryString += `${key}=${filtered[key]}&`;
});
// 3. 拼接密钥并生成MD5签名
const signString = queryString.slice(0, -1) + SECRET_KEY;
//加密方式(md5或sha1)与配置对应
return crypto.createHash('md5')
.update(signString)
.digest('hex')
.toUpperCase();
}
}
// 测试用例
const testParams = {
appId: 'APP123',
timestamp: Math.floor(Date.now() / 1000),
nonce: crypto.randomBytes(4).toString('hex'),
sign: 'should_be_removed',
emptyParam: null
};
console.log('Node签名结果:', SignGenerator.generate(testParams));
b、Java签名
import org.apache.commons.codec.digest.DigestUtils;
import java.util.TreeMap;
public class SignatureUtils {
private static final String SECRET_KEY = "your_secret_key_here";
public static String generate(Map<String, Object> params) {
// 1. 移除签名字段并过滤空值
Map<String, Object> filtered = new TreeMap<>();
params.forEach((k, v) -> {
if (!k.equals("sign") && v != null) {
filtered.put(k, v.toString());
}
});
// 2. 拼接排序后的参数
StringBuilder query = new StringBuilder();
filtered.forEach((k, v) -> query.append(k).append("=").append(v).append("&"));
String signString = query.substring(0, query.length()-1) + SECRET_KEY;
// 3. 生成大写MD5签名
return DigestUtils.md5Hex(signString).toUpperCase();
}
public static void main(String[] args) {
Map<String, Object> testParams = new HashMap<>();
testParams.put("appId", "APP123");
testParams.put("timestamp", System.currentTimeMillis()/1000);
testParams.put("nonce", "abcd1234");
System.out.println("Java签名结果: " + generate(testParams));
}
}