附录一 签名规则
签名校验适用于主动请求类接口,如下单接口
签名结构: sign = MD5(createBy+&+dataSource+&+JSON.toJSONString(request)+&+SK+&+timestamp)
签名规则说明:
1,签名采用md5方式加密;
2,参数中request字段值需转换为jsonstring类型,jsonstring中所有层级的值按key值的升序排列;
3,签名有效期为10分钟,故每次请求需获取当前时间戳;
4,鸿讯提供createBy,dataSource,SK;
5,生成签名后,将生成的签名赋给参数中的sign字段;
/**
- 生成签名示例
- @param param 接口参数
- @param sk 密钥
*/
public void sign(RequestDTO param,String sk){
JSONObject req=JSONObject.parseObject(param.getRequest());
String paramJson = SerializableUtil.marshal(req);
String message = param.getCreateBy()+"&"+param.getDataSource()+"&"+ paramJson+"&"+sk+"&"+param.getTimestamp();
String sign =DigestUtils.md5DigestAsHex(message.getBytes("utf-8"));
param.setSign(sign);
}
/**
-
@author :
-
@date :
-
@description:序列化工具
-
@modified By:
*/
public class SerializableUtil {
// 序列化参数
// 如果要自己实现,则必须保证这三点:
// 1、保证JSON所有层级上Key的有序性
// 2、保证JSON的所有数值不带多余的小数点
// 3、保证转义逻辑与这段代码一致
public static String marshal(Object o) {
String raw = CustomGson.toJson(o);
Map m = CustomGson.fromJson(raw, LinkedTreeMap.class); // 执行反序列化,把所有JSON对象转换成LinkedTreeMap
return CustomGson.toJson(m); // 重新序列化,保证JSON所有层级上Key的有序性
}private static final Gson CustomGson = new GsonBuilder()
.registerTypeAdapter(LinkedTreeMap.class, newMapSerializer()) // 定制LinkedTreeMap序列化,确保所有key按字典序排序
.registerTypeAdapter(Integer.class, newNumberSerializer()) // 定制数值类型的序列化,确保整数输出不带小数点
.registerTypeAdapter(Long.class, newNumberSerializer()) // 同上
.registerTypeAdapter(Double.class, newNumberSerializer()) // 同上
.disableHtmlEscaping() // 禁用Html Escape,确保符号不转义:&<>='
.create();// 为LinkedTreeMap定制的序列化器
public static JsonSerializer<LinkedTreeMap> newMapSerializer() {
return new JsonSerializer<LinkedTreeMap>() {
@Override
public JsonElement serialize(LinkedTreeMap src, Type typeOfSrc, JsonSerializationContext context) {
List keys = src.keySet().stream().map(Object::toString).sorted().collect(Collectors.toList());
JsonObject o = new JsonObject();
for (String k : keys) {
o.add(k, context.serialize(src.get(k)));
}
return o;
}
};
}// 为Number定制化的序列化器
private static JsonSerializer newNumberSerializer() {
return new JsonSerializer() {
@Override
public JsonElement serialize(T number, Type type, JsonSerializationContext context) {
if (number instanceof Integer) {
return new JsonPrimitive(number.intValue());
}
if (number instanceof Long) {
return new JsonPrimitive(number.longValue());
}
if (number instanceof Double) {
long longValue = number.longValue();
double doubleValue = number.doubleValue();
if (longValue == doubleValue) {
return new JsonPrimitive(longValue);
}
}
return new JsonPrimitive(number);
}
};
}
}