Java 接口签名 (Signature) 实现计划
大家好,我是程序员田同学!
今天上午收到一个需要,针对以后的零碎开发一个对外开放的接口。
既然是对外开放,那么调用者肯定没有咱们零碎的 Token,就须要对调用者进行签名验证,签名验证采纳支流的验证形式,采纳 Signature 的形式。
一、要求
下图为具体要求
二、流程
1、线下调配 appid 和 appsecret,针对不同的调用方调配不同的 appid 和 appsecret
2、退出timestamp(工夫戳),10 分钟内数据无效
3、退出流水号noncestr(避免反复提交),至多为 10 位。针对查问接口,流水号只用于日志落地,便于前期日志核查。针对办理类接口需校验流水号在有效期内的唯一性,以防止反复申请。
4、退出signature,所有数据的签名信息。
三、实现
简略来说,调用者调用接口业务参数在 body 中传递,header 中额定减少四个参数 signature、appkey、timestamp、noncestr。
咱们在后盾取到四个参数,其后三个参数加上调用者调配的 appSecret,应用字典排序并应用 MD5 加密后与第一个参数 signature 进行比对,统一既示意调用者有权限调用。
以下代码为接口验证签名的 demo 实现:
// 援用 jackson 依赖
@Autowired
private ObjectMapper objectMapper;
@Value("${appsecret}")
private String appSecret;
/**
* 验证签名
* @param preInfoItem
* @return
*/
boolean checkSignature(PreInfoItem preInfoItem) throws JsonProcessingException, IllegalAccessException {
String signature="signature";
String appkey="appkey";
String timestamp="timestamp";
String noncestr="noncestr";
HttpServletRequest request = ServletUtils.getRequest();
String headerSignature = request.getHeader(signature);
String headerAppkey = request.getHeader(appkey);
String headerTimestamp = request.getHeader(timestamp);
String headerNoncestr = request.getHeader(noncestr);
// 因为须要排序,间接应用 TreeMap
Map<String,Object> parms=new TreeMap<>();
parms.put(appkey,headerAppkey);
parms.put(timestamp,headerTimestamp);
parms.put(noncestr,headerNoncestr);
Map<String, Object> stringObjectMap = objectToMap(parms, preInfoItem);
String s = buildSignature(stringObjectMap);
// 签名比对
if (s.equals(headerSignature)){return true;}
return false;
}
Map<String,Object> objectToMap(Map<String,Object> map,Object o){Field[] declaredFields = o.getClass().getDeclaredFields();
for (Field field : declaredFields) {field.setAccessible(true);
try {if (field.getName() instanceof String){map.put(field.getName(),field.get(o));
}
}catch (IllegalAccessException e){throw new CustomException("对象转 map 异样");
}
}
return map;
}
private String buildSignature(Map<String,Object> maps){
String s2;
try {
StringBuffer s = null;
String s1 = objectMapper.writeValueAsString(maps);
// 增加 appSecret
s.append(s1).append(appSecret);
s2 = DigestUtils.md5DigestAsHex(s.toString().getBytes());
}catch (JsonProcessingException e){throw new CustomException("map 转 json 异样");
}
return s2;
}
好啦,赶快去试一下吧!