有独自开发一个Java的项目,项目中有对接到 美团餐饮开放平台,当时做的功能是将美团App的订单通过url回调给自己的系统,当作一笔新的订单做相应的逻辑后入库。
结果在回调请求的验证签名时卡了好一会,因为 美团餐饮开放平台 的请求比较特殊
1: 推送API会持续更新,所以接收参数不能使用固定的Form进行接收。
2: 参数均为普通Post参数而非Json,Content-Type字段为text,所以要用特别的方式进行接收。
计算签名:官方提供的SDK自己试了一遍,可能是自己用的方式不对,自己生成的Sig和请求的Sig一直对不上,所以自己动手写了一个校验签名的Demo
以下是生成签名的文档介绍,也可以查看官方文档
创建一个Controller来接收美团发起的回调请求:
1: 回调的参数不固定,这里使用 HttpServletRequest 对象来获取所有的参数
2: 字母排序的话,直接使用 TreeMap 搞定
package com.demo.www.controller.openapi;
import com.google.common.base.Joiner;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.TreeMap;
/**
* 美团餐饮开放平台回调接口
* @author AnYuan
*/
@RestController
public class DemoController {
/**
* 签名的字段名
*/
private final static String SIG_FIELD_NAME = "sig";
/**
* 校验签名
* @param request HttpServletRequest对象
* @return 签名是否正确
*/
public Boolean checkSign(HttpServletRequest request) {
String url = String.format("%s://%s%s", request.getScheme(), request.getServerName(), request.getRequestURI());
TreeMap<String, String> treeMap = new TreeMap<>();
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String value = request.getParameter(name);
if (!SIG_FIELD_NAME.equals(name)) {
treeMap.put(name, value);
}
}
String sign = sign(url, treeMap);
if (sign.equals(request.getParameter(SIG_FIELD_NAME))) {
System.out.println("签名正确");
return true;
}
System.out.println("签名错误");
return false;
}
/**
* 生成签名
* @param url 请求的完整的url
* @param treeMap 请求的全部参数
* @return sign
*/
private String sign(String url, TreeMap<String, String> treeMap) {
String queryString = Joiner.on("&").useForNull("").withKeyValueSeparator("=").join(treeMap);
String md5str = url.concat("?").concat(queryString).concat("美团开放平台的APP密钥");
try {
return DigestUtils.md5DigestAsHex(URLDecoder.decode(md5str, "UTF-8").getBytes());
} catch (UnsupportedEncodingException encodingException) {
System.out.println("签名生成失败");
}
return "";
}
}
这里 “美团餐饮开放平台的APP密钥” 是美团开发后台创建引用后获取的,不要直接写在代码里面,建议用配置文件进行管理。