接口签名文档
功能说明:第三方通过接口扩展业务功能(合作伙伴开放)。
1、应用接口"授权"配置 (应用管理)


2、生成签名"凭证"
签名生成流程
参数排序与拼接:将请求参数(除secret外)按字母升序排列,拼接为
key1=value1&key2=value2格式的字符串密钥混合:在字符串尾部拼接
secretKey参数值(如paramStr + secretKey)14。加密处理:使用MD5或SHA-1算法生成32位大写签名(如
DigestUtils.md5Hex)15。
验证机制
服务端通过相同规则生成签名,比对客户端传入的sign值,若不一致则拒绝请求
需注意时间戳(timestamp)防重放攻击,通常设置5分钟有效期
头部设置 Content-Type
数据编码支持:multipart/form-data、application/x-www-form-urlencoded 、application/json
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['sign'] == $this->createSign($resArray)){
//返回业务数据
return $resArray;
}else{
echo "--------校验错误----------";
return $resArray;
}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));
}
}