签名机制
签名机制
概述
API接口服务会对每个访问的请求进行身份验证,所以无论使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(sign)信息。
签名步骤
API服务接口通过使用appid和secret进行对称加密的方法来验证请求的发送者身份,每个接口必须填写以下公共参数:
参数名 | 类型 | 必选 | 参数说明 |
---|---|---|---|
appid | string | 是 | 开通API服务时获取的平台唯一id |
expired | int | 否 | 签名失效的unix时间戳,建议当前时间5分钟后 |
sign | string | 是 | 请求接口的参数生成的签名,详细生成规则见 (签名机制) |
签名规则
请将请求URL 拼接上 排序拼接后的POST的数据 拼接上 秘钥字符串,然后对拼接出来的字符串计算MD5值。
伪代码示例
// 接口地址
url = https://api.zmengzhu.com/message/delete
// 密钥id与secret
appid = 20191008135xxxxxxxx
secret = Nd9zTE1eli1PlKy4ZdSsKAWpiNNsOOEaAfUzOxVcGvDC47q5QYX1pJtfJZLPkr0q
// 接口请求有效期,当前时间戳加5分钟
expired = nowTimeStamp + 300
// 拼接url参数 注意如有GET请求参数,可以依次添加,参数顺序不做要求
url = url + '?appid=' + appid + '&expired=' + expired;
// POST参数非必须,GET请求方式时,postDataMap为空
postDataMap = [
'ticket_id' => 2
'msg_id' => 1,
];
// 如有POST数据,需要对postDataMap内容进行排序,以索引名正序排序
ksort(postDataMap);
// 排序后的结果
/*
postDataMap = [
'msg_id' => 1
'ticket_id' => 2,
];
*/
// 如有POST数据,需要拼接POST参数,拼接POST数据的key和value
postString = '';
for (key in postDataMap)
postString = postString + key + postDataMap[key]
// 拼接后postString的值为 msg_id1ticket_id2
// 开始签名 注意postString可以为空, urlSuffix 为去除请求协议后的地址,
// 如 url = 'http://www.zmengzhu.com' 则 urlSuffix = 'www.zmengzhu.com'
urlSuffix = preg_replace(/^https?:\/\//, '', url)
sign = md5(urlSuffix + postString + secret)
// 最终完整请求URL
url = url + '&sign=' + sign;
代码示例 (Java版本)
package test;
import java.security.MessageDigest;
import java.util.*;
public class SignDemo {
public static void main(String[] args) {
SignDemo demo=new SignDemo();
// 以下为post请求签名方式
// Map<String, String> postParam = new LinkedHashMap<>();
// postParam.put("offset","0");
// postParam.put("limit","10");
// String sign=demo.md5Sign(demo.noHttpUrl("http://api.t.zmengzhu.com/business/v1/channel/lists?appid=2019091711385214738"),
// demo.sortparams(postParam),"BKyE0nD7q0dRPHw5PxGL83LLnx8Pcu90GRBFnhfGwFnlmE7iO6wFI7FZsYu6Ir6e");
// System.out.println("http://api.zmengzhu.com/business/v1/xxx/xxxxx?appid=xxxx"+"&"+"sign="+sign);//完整的请求地址
// 以下为get请求签名方式
String sign=demo.md5Sign(demo.noHttpUrl("http://api.zmengzhu.com/business/v1/xxx/xxxxx?appid=xxxx&参数key=值&参数key=值"),
null,"密钥");
System.out.println("http://api.zmengzhu.com/business/v1/xxx/xxxxx?appid=xxxx&参数key=值&参数key=值"+"&"+"sign="+sign);//完整的请求地址
}
public Map<String,Object> sortparams(Map<String,String> params){
Map<String,Object> result=new LinkedHashMap<>();
List<Map.Entry<String,String>> list = new ArrayList<Map.Entry<String,String>>(params.entrySet());
Collections.sort(list,new Comparator<Map.Entry<String,String>>() {
//升序排序
public int compare(Map.Entry<String, String> o1,
Map.Entry<String, String> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
for(Map.Entry<String,String> mapping:list){
result.put(mapping.getKey(),mapping.getValue());
System.out.println(mapping.getKey()+":"+mapping.getValue());
}
return result;
}
/**
* 去掉请求头
* @param urlHttp
* @return
*/
private String noHttpUrl(String urlHttp){
if(urlHttp.contains("http://")){
return urlHttp.replace("http://","");
}else if(urlHttp.contains("https://")){
return urlHttp.replace("https://","");
}
return urlHttp;
}
/**
* 获取sign
* @param url 去除前缀的绝对路径
* @param postParam post 参数传入
* @param secretKey
* @return
*/
public static String md5Sign(String url, Map<String, Object> postParam,String secretKey) {
StringBuilder sb=null;
String sign="";
if (postParam != null && postParam.size() > 0) {
sb = new StringBuilder();
if (postParam != null && postParam.size() > 0) {
List<String> paramNames = new ArrayList<String>(postParam.size());
paramNames.addAll(postParam.keySet());
for (String paramName : paramNames) {
String value = String.valueOf(postParam.get(paramName));
sb.append(paramName).append(value);
}
}
}
if (sb != null && !isEmpty(sb)) {
System.out.println(url + sb.toString() + secretKey);
sign= getMd5(url + sb.toString() + secretKey);
}else {
System.out.println(url + secretKey);
sign=getMd5(url + secretKey);
}
return sign;
}
public static boolean isEmpty(StringBuilder string){
if(string==null||string.equals("")||string.length()==0){
return true;
}else {
return false;
}
}
public static String getMd5(String value) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(value.getBytes());
return toHexString(md5.digest());
} catch (Throwable e) {
e.printStackTrace();
}
return "";
}
private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
public static String toHexString(byte[] b) {
StringBuilder sb = new StringBuilder(b.length * 2);
for (int i = 0; i < b.length; i++) {
sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
sb.append(HEX_DIGITS[b[i] & 0x0f]);
}
return sb.toString();
}
}
代码示例 (PHP版本)
$appid = "xxx"; // 开通平台获取的appid
$secret = "xxx"; // 开通平台获取的secret
$mzServiceUrl = 'http://api.zmengzhu.com'; // 盟主接口服务域名
$action = '/live/create'; // 请求服务操作
$params = [
"appid" => $appid,
"expired" => time() + 300,
// 此处可以添加其他业务接口单独需要的参数
];
$urlSuffix = str_replace(['http://', 'https://'], '', $mzServiceUrl) . $action . '?' . http_build_query($params);
$postData = [
// 需要post请求的参数
];
$sortString = '';
if ($postData) {
ksort($postData);
foreach ($postData as $k => $v) {
$sortString .= $k.$v;
}
}
return md5($urlSuffix . $sortString . $secret);