跳到主要内容

安全性

签名实现

假设现在某 API 需要 3 个业务参数,分别是 k1, k2, k3, 它们的值按顺序对应分别是 v1, v2, v3,接口提供方和调用方协商的密钥为 secretKey, 那么此接口的签名参数 sign 计算方式为:

  1. 将请求中所有业务参数 (不包括 sign 和 value 为空的参数) 按字典序升序排列k1=v1&k2=v2&k3=v3 形式拼接得到 unsignedWithoutKey
  2. 在第 1 步的得出结果 unsignedWithoutKey 尾部,追加双方约定的 secretKey, 得到 unsigned
  3. 将第 2 步得到的结果 unsigned 进行 MD5 编码(32 位小写形式)再转成 HexString,得到 sign
提示
  • 第一步中参数拼接时,去除 value 为空的参数
  • 第一步中参数拼接时,使用实际参数值【先进行 urlDecode 】
  • 参数排序,按字典序升序排列
  • secretKey 为 SGSDK 平台相关人员提供的 产品集成反馈【应用密钥】

示例参数

建议

建议签名方法编写完成后,用此 Demo 进行测试

假设某接口双方约定的 secretKey=480ednmfzssqs8jz ,请求参数中业务参数包括 caller=kingsoftgametime=1489460391extra=msg=test space, 其中包含 value 为空的参数 extra,value 带空格的参数 msg

该接口的 sign 签名计算方式为:

// 第一步
// 参数 extra 的 value 为空,拼接时去除。
// 按 key 字段排序后顺序,[calller,msg,time],
unsignedWithoutKey = "caller=kingsoftgame&msg=test space&time=1489460391";

//第二步
unsigned = unsignedWithoutKey + secretKey ;
// unsigned = "caller=kingsoftgame&msg=test space&time=1489460391480ednmfzssqs8jz"

//第三步
sign = Md5Utils.encode(unsigned);
//sign="857db83778e1c67172ca2c2e9cca1e55";

示例代码

package com.sgxsj.game.docs;

import java.util.Objects;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.security.MessageDigest;

public class JavaSignDemo {

private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

private static String secretKey = "480ednmfzssqs8jz";

public static void getSign(String sign) {
Map<String, Object> apiParams = new HashMap<>();
apiParams.put("caller", "kingsoftgame");
apiParams.put("msg", "test space");
apiParams.put("extra", "");
apiParams.put("time", "1489460391");
String unSignData = getSignData(apiParams);
System.out.println("unSignData:" + unSignData);
System.out.println("MD5String:" + unSignData + secretKey);
String md5Sign = MD5Encode(unSignData + secretKey);
System.out.println("MD5Encode:" + md5Sign);
boolean result = checkSign(md5Sign, sign);
System.out.println("check sign result:" + result);
}

public static String getSignData(Map<String, Object> params) {
StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
if ("sign".equals(key) || "Sign".equals(key) || "sign_type".equals(key)) {
continue;
}
String value = String.valueOf(params.get(key));
if (Objects.isNull(value) || value.isEmpty()) {
continue;
}
if (i != 0) {
content.append("&");
}
content.append(key).append("=").append(value);
}
return content.toString();
}

public static boolean checkSign(String md5Sign, String requestSign) {
if(!requestSign.equals(md5Sign)){
return false;
} else {
return true;
}
}

public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteArrayToHexString(md.digest(resultString.getBytes("UTF-8")));
} catch (Exception ex) {

}
return resultString;
}

public static String byteArrayToHexString(byte[] b) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}

private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}

public static void main(String[] args) {
String sign = "857db83778e1c67172ca2c2e9cca1e55";
getSign(sign);
}
}