签名机制¶
签名说明¶
- 公共参数(
sign除外) + 私有参数+appsecret一起按照字典升序排列后以“&”相接 - 切记
appsecret只参与签名,不参与传递 - 公共参数和私有参数里非必传字段不是必须参与签名和传递的,
任何参数如果参与了签名,就一定要参与传递,否则签名不通过 - 令牌创建-接口是没有公用参数,只需私有参数参与签名,见如下令牌创建签名示例
- 公共参数 的传递都是放在queryString或表单之中,不能放在别的位置
- 私有参数根据Content-Type分为两类:
application/x-www-form-urlencoded和application/json,具体使用哪种查看每个接口里的 请求示例 部分 - 绝大部分接口均是表单传参形式
application/x-www-form-urlencoded,
签名方式参考form传参业务签名示例 - 少量接口是需要传递大量数据的业务情况下,传参形式为
application/json,
签名方式参考json传参业务签名示例
令牌创建签名示例¶
-
假设私有参数如下:
-
假设appsecret如下
-
对上述所有参数进行字典升序排列。排好序的参数信息依次为
-
以&拼接排好序的参数,参数的形式为key=value,拼接结果如下
-
生成签名
-
java签名代码如下:
import org.apache.commons.codec.digest.DigestUtils; import java.util.Iterator; import java.util.Map.Entry; import java.util.TreeMap; public class Signs { public static void main(String[] args) { int appId = 30000003; String appSecret = "f4cc82386a1cdddcc98e4f53b1115a62"; int timeStamp = 1469691921; String grantType = "client_credential"; TreeMap<String, Object> params = new TreeMap(); params.put("appid", appId); params.put("grant_type", grantType); params.put("timestamp", timeStamp); params.put("appsecret", appSecret); StringBuilder stringBuilder = new StringBuilder(); Iterator tmp = params.entrySet().iterator(); while (tmp.hasNext()) { Entry<String, Object> entry = (Entry) tmp.next(); stringBuilder.append(((String) entry.getKey()).trim()); stringBuilder.append("="); stringBuilder.append(entry.getValue().toString().trim()); stringBuilder.append("&"); } stringBuilder.deleteCharAt(stringBuilder.length() - 1); String signContent = stringBuilder.toString(); System.out.println("打印签名字符串:" + signContent); String sign = DigestUtils.sha256Hex(signContent); System.out.println("签名结果sign:" + sign); } } 运行结果: 打印签名字符串:appid=30000003&appsecret=f4cc82386a1cdddcc98e4f53b1115a62&grant_type=client_credential×tamp=1469691921 签名结果sign:45dc064aa755ac2146aa24cf7baea3cf3668970538fba7b70ccef39a3ad055b1
form传参业务签名示例¶
- 假设公共参数如下:
-
假设私有参数如下:
-
假设appsecret如下
-
对上述所有参数进行字典升序排列。排好序的参数信息依次为
-
以&拼接排好序的参数,参数的形式为key=value,拼接结果如下
-
生成签名
-
java签名代码如下:
import org.apache.commons.codec.digest.DigestUtils; import java.util.Iterator; import java.util.Map.Entry; import java.util.TreeMap; public class Signs { public static void main(String[] args) { //公共参数 String accessToken = "1ba50b8f418a3ceeba989d7b789de149"; int timeStamp = 1469691921; String grantType = "client_credential"; //私有参数 String name = "alask"; String remark = "传参示例"; //密钥 String appSecret = "f4cc82386a1cdddcc98e4f53b1115a62"; //使用TreeMap会自动将key按照字典升序排列 TreeMap<String, Object> params = new TreeMap(); params.put("access_token", accessToken); params.put("grant_type", grantType); params.put("timestamp", timeStamp); params.put("name", name); params.put("remark", remark); params.put("appsecret", appSecret); StringBuilder stringBuilder = new StringBuilder(); Iterator tmp = params.entrySet().iterator(); while (tmp.hasNext()) { Entry<String, Object> entry = (Entry) tmp.next(); stringBuilder.append(((String) entry.getKey()).trim()); stringBuilder.append("="); stringBuilder.append(entry.getValue().toString().trim()); stringBuilder.append("&"); } //移除最后拼接的&符号 stringBuilder.deleteCharAt(stringBuilder.length() - 1); String signContent = stringBuilder.toString(); System.out.println("打印签名字符串:" + signContent); //256签名转16进制 String sign = DigestUtils.sha256Hex(signContent); System.out.println("签名结果sign:" + sign); } } 运行结果: 打印签名字符串:access_token=1ba50b8f418a3ceeba989d7b789de149&appsecret=f4cc82386a1cdddcc98e4f53b1115a62&grant_type=client_credential&name=alask&remark=传参示例×tamp=1469691921 签名结果sign:b4463c7b809416fc30640ec8ffca2ab95f80584c96f731d9ec80119b5cfebdf8
json传参业务签名示例¶
- 假设公共参数如下:
-
假设私有参数json如下:
-
假设appsecret如下
-
将上述json中数据在本地以
_body参数参与到私有参数中做排序和签名 -
对上述所有参数进行字典升序排列。排好序的参数信息依次为
-
以&拼接排好序的参数,参数的形式为key=value,拼接结果如下
-
生成签名
sign=sha256(_body=[{"name":"alask1","remark":"传参示例1"},{"name":"alask2","remark":"传参示例2"}]&access_token=1ba50b8f418a3ceeba989d7b789de149&appsecret=f4cc82386a1cdddcc98e4f53b1115a62&grant_type=client_credential×tamp=1469691921) 计算结果为:8abb42eb9c342063a01f1cc2ea3cafe0cce5a53efd44d51ea0a72a9e82b97b69 开发者可以用这个示例检查自己的sha256算法是否有效 -
json格式传参时,注意不需要将
_body参数传递,只需要把私有参数放在json体中即可,公共参数放在queryString或者表单中都可以 -
java签名代码如下:
import com.alibaba.fastjson.JSONArray; import org.apache.commons.codec.digest.DigestUtils; import java.util.*; import java.util.Map.Entry; public class Test { public static void main(String[] args) { //公共参数 String accessToken = "1ba50b8f418a3ceeba989d7b789de149"; int timeStamp = 1469691921; String grantType = "client_credential"; //私有参数 List<Map<String, Object>> dataList = new ArrayList<>(); Map<String, Object> map1 = new HashMap<>(); map1.put("name", "alask1"); map1.put("remark", "传参示例1"); Map<String, Object> map2 = new HashMap<>(); map2.put("name", "alask2"); map2.put("remark", "传参示例2"); dataList.add(map1); dataList.add(map2); JSONArray jsonArray = new JSONArray(); jsonArray.addAll(dataList); String _body = jsonArray.toString(); System.out.println("打印json字符串:" + _body); //密钥 String appSecret = "f4cc82386a1cdddcc98e4f53b1115a62"; //使用TreeMap会自动将key按照字典升序排列 TreeMap<String, Object> params = new TreeMap(); params.put("access_token", accessToken); params.put("grant_type", grantType); params.put("timestamp", timeStamp); params.put("_body", _body); params.put("appsecret", appSecret); StringBuilder stringBuilder = new StringBuilder(); Iterator tmp = params.entrySet().iterator(); while (tmp.hasNext()) { Entry<String, Object> entry = (Entry) tmp.next(); stringBuilder.append((entry.getKey()).trim()); stringBuilder.append("="); stringBuilder.append(entry.getValue().toString().trim()); stringBuilder.append("&"); } //移除最后拼接的&符号 stringBuilder.deleteCharAt(stringBuilder.length() - 1); String signContent = stringBuilder.toString(); System.out.println("打印签名字符串:" + signContent); //sha256签名转16进制 String sign = DigestUtils.sha256Hex(signContent); System.out.println("签名结果sign:" + sign); } } 运行结果: 打印json字符串:[{"name":"alask1","remark":"传参示例1"},{"name":"alask2","remark":"传参示例2"}] 打印签名字符串:_body=[{"name":"alask1","remark":"传参示例1"},{"name":"alask2","remark":"传参示例2"}]&access_token=1ba50b8f418a3ceeba989d7b789de149&appsecret=f4cc82386a1cdddcc98e4f53b1115a62&grant_type=client_credential×tamp=1469691921 签名结果sign:8abb42eb9c342063a01f1cc2ea3cafe0cce5a53efd44d51ea0a72a9e82b97b69
请求注意事项¶
-
请勿将
appsecret参与到http请求传递中,它是双方保管的密钥,一旦泄露,请申请更换。 -
传参编码统一使用UTF-8;
-
key和value的首尾请不要有空格,不然容易出现签名错误。