这里接着上一篇微信支付开始 (https://blog.csdn.net/qq_39897814/article/details/88890484)
以下是微信支付的回调,可能有人在这里的回调中的验签不通过也可以看一下,因为我也是一开始没通过,经过各种查资料最终成功
其实微信支付回调的验签就是讲微信回调返回给你的全部数据除去sign外中心加密一次和微信回调返回的sign进行对比,一致就通过,不一致说明有风险有可能被改过,所以有回调验签不通过的朋友可以将微信回调的sign先提出来 然后从返回的数据中心去掉在重新加密对比 也可以继续往下看
/**
*微信支付回调
*/
@RequestMapping("notify")
public String notify(HttpServletRequest request) {
log.info("================================================开始处理微信小程序发送的异步通知");
//1 获取微信支付异步回调结果
String xmlResult = WeiXinPayUtil.getPostStr(request);
Map resultMap = null;
try {
//将结果转成map
resultMap = WXPayUtil.xmlToMap(xmlResult);
} catch (Exception e1) {
e1.printStackTrace();
}
//订单号
String orderNo = resultMap.get("out_trade_no");
log.info("订单号:------------------"+orderNo+"结束----------");
String result_code = resultMap.get("result_code");
//回调返回的加密签名 保存下来 下面会进行对比
String sign = resultMap.get("sign");
//去掉sign和利用微信回调回来的信息重新加密
resultMap.remove("sign");
String sign1="";
try {
//重新加密 获取加密的签名
sign1=WXPayUtil.generateSignature(resultMap, WXMiniPayConfig.KEY); //签名
}catch (Exception e){
}
String resultCode;
String resultMsg;
//对比微信回调的加密与重新加密是否一致 一致即为通过 不一致说明呗改动过 加密不通过
log.info("==============================================开始对比加密++++++++++++++++++++++++++++++++++++++");
if (sign.equals(sign1)) { //验签通过
log.info("==============================================验签通过++++++++++++++++++++++++++++++++++++++");
if (WXPayEnum.isPaymentSuccess(result_code)) {//业务结果为SUCCESS
/**
* 这里写你要处理的逻辑
*/
resultCode = "SUCCESS";
resultMsg = "成功";
} else { // 业务结果为FALL
resultCode = "FAIL"
resultMsg = "业务结果为FAIL";
}
} else {
resultCode = "FAIL";
resultMsg = "验签未通过";
}
Map returnMap = new HashMap<>();
returnMap.put("return_code", resultCode);
returnMap.put("return_msg", resultMsg);
try {
String s = WXPayUtil.mapToXml(returnMap);
return s;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
这样结果就通过了,有回调前名验证没通过的朋友 要好好看看代码中的注释
所需工具类
public class WeiXinPayUtil {
/**
* 微信回调参数解析
*
* @param request
* @return
*/
public static String getPostStr(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
try {
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String s = "";
while ((s = br.readLine()) != null) {
sb.append(s);
}
} catch (IOException e) {
e.printStackTrace();
}
String xml = sb.toString(); //次即为接收到微信端发送过来的xml数据
return xml;
}
public class WXMiniPayConfig {
//api秘钥 从微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 获取
public static final String KEY = "";
// 微信支付分配的公众账号ID(企业号corpid即为此appId)
public static final String APP_ID = "";
//微信支付分配的商户号
public static final String MCH_ID = "";
}
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.*;
import java.security.MessageDigest;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import com.github.wxpay.sdk.WXPayConstants.SignType;
public class WXPayUtil {
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map xmlToMap(String strXML) throws Exception {
Map data = new HashMap();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx=0; idx data) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document document = documentBuilder.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key: data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @return 含有sign字段的XML
*/
public static String generateSignedXml(final Map data, String key) throws Exception {
return generateSignedXml(data, key, SignType.MD5);
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名类型
* @return 含有sign字段的XML
*/
public static String generateSignedXml(final Map data, String key, SignType signType) throws Exception {
String sign = generateSignature(data, key, signType);
data.put(WXPayConstants.FIELD_SIGN, sign);
return mapToXml(data);
}
/**
* 判断签名是否正确
*
* @param xmlStr XML格式数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
Map data = xmlToMap(xmlStr);
if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
return false;
}
String sign = data.get(WXPayConstants.FIELD_SIGN);
return generateSignature(data, key).equals(sign);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
*
* @param data Map类型数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(Map data, String key) throws Exception {
return isSignatureValid(data, key, SignType.MD5);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名方式
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(Map data, String key, SignType signType) throws Exception {
if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
return false;
}
String sign = data.get(WXPayConstants.FIELD_SIGN);
return generateSignature(data, key, signType).equals(sign);
}
/**
* 生成签名
*
* @param data 待签名数据
* @param key API密钥
* @return 签名
*/
public static String generateSignature(final Map data, String key) throws Exception {
return generateSignature(data, key, SignType.MD5);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static String generateSignature(final Map data, String key, SignType signType) throws Exception {
Set keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public static String generateNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String MD5(String data) throws Exception {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
/**
* 生成 HMACSHA256
* @param data 待处理数据
* @param key 密钥
* @return 加密结果
* @throws Exception
*/
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
}