学习记录:接口参数MD5算法校验
签名算法过程
对除签名外的所有请求参数按key做ASCII升序排列,value无需编码。(假设当前时间的时间戳是12345678)
例如:一共有三个参数,a=10,b=11,c=12,那么再加上时间戳之后就是四个参数,按Key做ASCII升序排列之后,> 得到拼装的字符串,a10b11c1212345678,当然加不加参数名这些规则由你来定
用约定好的appkey来拼装到字符串的头部和尾部:
appkey+a10b11c1212345678+appkey
然后进行32位MD5加密,最后转大写。
这只是你需要接受的sign签名,除此之外,还需要接受包括在sign之中的所有参数,例如时间戳等等。
在你接受到参数之后,你同样要再次进行一遍MD5加密,然后与sign进行匹配,如果相同的话则签名正确,否则签名失败。
以下是例子:
/**
* MD5加密工具类
* @param src 需要加密的字符串
* @return
*/
public class EncryptionUtil {
public final static String MD5(String src) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
try {
byte[] btInput = src.getBytes("UTF-8");
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
controller:
@RestController
@RequestMapping("/scanCode")
public class ScanCodeBuyController {
@Autowired
private ScanCodeBuyService scanCodeBuyService;
/**
* 扫码购
* @param 'sign' 签名
* @param 'productname' 商品名称
* @param 'productno' 商品编号
* @param 'timestamp' 时间戳
* @param 'page' 当前页码
* @param 'pageSize' 每页条数
* @return
*/
@PostMapping("/provideProduct")
public ResultMsg provideProduct(@RequestBody Map<String,String> map){
return scanCodeBuyService.provideProduct(map);
}
}
service就不贴出来了
以下是serviceImpl:
@Service
public class ScanCodeBuyServiceImpl implements ScanCodeBuyService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${product.ScanCodeBuy.MD5Key}")
private String MD5Key; //MD5约定的key我放在了数据库中
@Autowired
private ESIndexService esIndexService; //feign中用到的其他服务的方法
@Override
public ResultMsg provideProduct(Map<String, String> map) {
//ResultMsg是我的一个数据模型DTO
//验证签名
ResultMsg msg = checkSign(map);
ResultMsg esMsg = new ResultMsg();
if (! msg.getResult()){
return msg;
}
try {
//........逻辑代码
}catch (Exception e){
logger.info("provideProduct======"+e);
esMsg.setRetcode("ES");
esMsg.setMsg("内部错误");
esMsg.setResult(false);
return esMsg;
}
return esMsg;
}
/**
* 签名校验
* @param sign
* @return
*/
public ResultMsg checkSign(Map<String, String> map){
ResultMsg msg = new ResultMsg();
if (StringUtils.isEmpty(map.get("productname"))) {
msg.setRetcode("P1");
msg.setMsg("productname不能为空");
msg.setResult(false);
return msg;
}
if (StringUtils.isEmpty(map.get("sign"))) {
msg.setRetcode("S1");
msg.setMsg("sign不能为空");
msg.setResult(false);
return msg;
}
if (StringUtils.isEmpty(map.get("productno"))) {
msg.setRetcode("P1");
msg.setMsg("productno不能为空");
msg.setResult(false);
return msg;
}
if (StringUtils.isEmpty(map.get("timestamp"))) {
msg.setRetcode("T1");
msg.setMsg("timestamp不能为空");
msg.setResult(false);
return msg;
}
if (StringUtils.isEmpty(map.get("page"))) {
msg.setRetcode("P1");
msg.setMsg("page不能为空");
msg.setResult(false);
return msg;
}
if (StringUtils.isEmpty(map.get("pageSize"))) {
msg.setRetcode("P1");
msg.setMsg("pageSize不能为空");
msg.setResult(false);
return msg;
}
String md5 = EncryptionUtil.MD5(MD5Key+map.get("page")
+map.get("pageSize")
+map.get("productname")
+map.get("productno")
+map.get("timestamp")
+MD5Key).toUpperCase();
logger.info("product===ScanCodeBuy==========md5本地签名"+md5);
logger.info("product===ScanCodeBuy==========sign传入签名"+map.get("sign"));
if (md5.equals(map.get("sign"))){
msg.setMsg("签名匹配");
msg.setResult(true);
return msg;
} else {
msg.setRetcode("S2");
msg.setMsg("签名不匹配");
msg.setResult(false);
return msg;
}
}
}