背景:为了增加接口参数安全,对接口参数加盐进行签名校验。
原理:客户端对传送的参数字典排序后,进行md5签名。服务器接收参数后,同理进行参数字典排序后md5签名。若客户端与服务端的签名一致,说明参数未被篡改,校验通过。
请求参数示例:
字段 | 数据 | 类型 | 描述 |
---|---|---|---|
phone | 158112341234 | String | 手机号 |
timestamp | 1538990392850 | long | 时间戳 |
deviceId | mo-231odvepqd | String | 设备id |
sign | 158112341234 | String | 接口签名,md5(参数字典排序后加盐) |
注:
1.参数排序时,不包括sign参数
2.加盐参数使用desKey,放在参数字典排序后的开头位置
3.遇到数值拼接时,需统一转换成字符串类型。如:123 需转换成 “123”
4.为避免客户端和服务器端签名对null处理不一致,若参数值为null时,请转换成空字符串("")
签名步骤
1.字段字典排序:
deviceId phone timestamp
2.参数拼接:
mo-231odvepqd1581123412341538990392850
3.加盐:
hechaojie.commo-231odvepqd1581123412341538990392850
这里加盐参数为:hechaojie.com,请注意安全存储。
4.md5签名:
21bf08491dbf4013a8e9275f1d603e4a
客户端发送数据示例:
{"phone":"158112341234","sign":"21bf08491dbf4013a8e9275f1d603e4a","deviceId":"mo-231odvepqd","timestamp":1538990392850}
服务器签名工具类示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import cn.hechaojie.common.core.encryption.MD5;
import cn.hechaojie.common.core.util.Constant;
/**
* 接口签名工具类
* @author hecj
*
*/
public class SignKit {
// 签名字段
final static String SIGN_FIELD = "sign";
/**
* 签名
* @param signObj
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static String sign(Object obj) {
if(obj instanceof Map) {
return MD5.md5crypt(getDictStr((Map)obj));
}
if(obj instanceof JSONObject) {
return MD5.md5crypt(getDictStr((JSONObject)obj));
}
throw new RuntimeException("暂时不支持此类型生成签名,"+obj.getClass());
}
/**
* JSONObject字段排序拼接
*/
public static String getDictStr(JSONObject obj) {
List<String> keys = new ArrayList<String>(obj.keySet());
keys.remove(SIGN_FIELD);
Collections.sort(keys);
StringBuffer str = new StringBuffer(Constant.ApiDesKey);
for(String key : keys) {
Object value = obj.get(key);
if(value == null) {
value = "";
}
str.append(String.valueOf(value));
}
return str.toString();
}
public static String getDictStr(Map<String,Object> obj) {
List<String> keys = new ArrayList<String>(obj.keySet());
keys.remove(SIGN_FIELD);
Collections.sort(keys);
StringBuffer str = new StringBuffer(Constant.ApiDesKey);
for(String key : keys) {
Object value = obj.get(key);
if(value == null) {
value = "";
}
str.append(String.valueOf(value));
}
return str.toString();
}
}
注:仅供参考,有更好的方案可@我,共同探讨。