设计方案
跟第三方系统打交道时一般会双方协商一组秘钥,然后将接口的参数进行约定的处理,防止接口被盗刷。
通用参数,在header上加入两个参数,参数信息如下:
| 参数名称 | 参数位置 |字段说明| 是否必须|
| —- | —- |—- |—- |
| sign | header |签名,将appid、secret、当前日期三个参数md处理 | 是|
| timestamp | header | 时间戳,到秒 | 是 |
签名字段sign说明:
将[appid | secret | 当前日期]进行md5加密取32位小写算法,比如:
appId: 12345
secret:123
当前日期:20201001
则sign=MD5(12345|123|20201001)=faa2626dbd47f0548d9622b1a748d672
要求
同一组参数只在10s内有效,考虑到服务器和客户端时间差,前后5秒有效。
备份代码
入口函数
public Boolean demo(HttpServletRequest request) {
String cubaSign = request.getHeader("sign");
String cubaTimestamp = request.getHeader("timestamp");
log.info("请求参数sign为【{}】,时间参数为【{}】", cubaSign, cubaTimestamp);
if (!isValidTimestamp(Long.valueOf(cubaTimestamp))) {
log.error("调用接口连接超时,请求时间戳为【{}】", cubaTimestamp);
return false;
}
if (!isValidSign(cubaSign)) {
log.error("调用接口sign校验不通过");
return false;
}
return true;
}
俩个验证函数
import org.apache.commons.codec.digest.DigestUtils;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* 校验sign
* 将[appid | secret | 当前日期]进行md5加密。
*/
private Boolean isValidSign(String cubaSign) {
String sign = appId + "|" + secret + "|" + DateUtil.date2str(new Date(), DateUtil.DAY_FORMAT);
String md5Sign = DigestUtils.md5Hex(sign).toUpperCase();
log.info("校验sign是否正确,md5机密后的sign【{}】", md5Sign);
return md5Sign.equals(cubaSign);
}
/**
* 校验时间戳
* 当前时间正负5秒之内的时间的时间戳
*/
private Boolean isValidTimestamp(Long cubaTimestamp) {
LocalDateTime localDateTime = LocalDateTime.now();
Long after5Time = localDateTime.plusSeconds(30).toEpochSecond(ZoneOffset.ofHours(8));
Long before5Time = localDateTime.plusSeconds(-30).toEpochSecond(ZoneOffset.ofHours(8));
return (before5Time < cubaTimestamp) && (cubaTimestamp < after5Time);
}