Java对接支付宝,回调验签失败
Java对接支付宝,回调验签失败
- 1.验签的方法使用
- 2.对于乱码的处理
- 相关依据
此处是我遇到问题时的解决办法,若不适用,请再寻他法
1.验签的方法使用
//若使用AlipayConfig.SIGN_TYPE = "RSA2",使用下面的验签方法
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, "UTF-8",AlipayConfig.SIGN_TYPE);
//若使用AlipayConfig.SIGN_TYPE = "RSA",使用下面的验签方法
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, "UTF-8");
2.对于乱码的处理
解析HttpServletRequest—>map 的时候注意,在没有出现乱码的情况时候不要加valueStr = new String(valueStr.getBytes(“ISO-8859-1”), “utf-8”);
否则可能导致验签失败
示例代码
// 1. 读取支付宝回调的参数并转换为Map
request.setCharacterEncoding("UTF-8");
Map < String, String > params = new HashMap < > ();
Map < String, String[] > requestParams = request.getParameterMap();log.info("【支付宝回调】请求ID:{},开始解析请求参数,参数数量:{}",requestId, requestParams.size());for (Iterator < String > iter = requestParams.keySet().iterator(); iter.hasNext();) {String name = iter.next();String[] values = requestParams.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";}// 解决可能的乱码问题// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");params.put(name, valueStr);log.debug("【支付宝回调】请求ID:{},解析参数:{}={}", requestId, name, valueStr);
}
代码里当我注释掉valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
反而可以验签成功
总结:
1.代码里在接收时设置
request.setCharacterEncoding("UTF-8");
2.具体的转map里不要再去用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8")
相关依据
签名验证本质上是对原始数据的哈希 / 加密校验,编码转换会直接改变字符串的字节序列,从而导致验签失败。
-
签名验证的核心逻辑
支付宝等第三方平台的回调签名,是基于原始请求参数的字节序列通过特定算法(如 RSA)生成的。验证签名时,系统会:
● 重新将当前参数按规则拼接成字符串
● 对该字符串的字节序列进行加密 / 哈希
● 与回调中传递的签名值对比,一致则验签通过 -
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
风险
逻辑:- 先将
valueStr按ISO-8859-1
编码转为字节数组(getBytes(“ISO-8859-1”)) - 再将字节数组按
UTF-8编码转回字符串
(new String(…, “UTF-8”))
风险:
- 如果valueStr中包含中文、特殊符号等非 ASCII 字符,ISO-8859-1是单字节编码,无法正确表示这些字符(
会用?或其他乱码替代
) - 此时通过ISO-8859-1获取的字节数组已经是 “损坏” 的,再用UTF-8转回字符串时,会产生与原始字符串完全
不同的字符序列
例如:
● 原始字符串"测试"的 UTF-8 字节是[-26, -75, -117, -25, -107, -116]
● 若按ISO-8859-1转换,会得到错误的字节数组(如[63, 63],63是?的 ASCII 码)
● 再转成 UTF-8 字符串可能变成"??",与原始值完全不同
对验签的直接影响:
● 改变参数中包含非 ASCII 字符的valueStr的实际内容(如中文变乱码)
● 导致重新拼接的参数字符串与支付宝生成签名时的原始字符串不一致
● 最终计算出的签名值与回调中的签名不匹配,验签失败
总结:
1.确保从请求中读取参数时就使用正确的编码(如支付宝回调默认是 UTF-8)
2.如果requestParams是从HttpServletRequest中获取的,应先通过request.setCharacterEncoding(“UTF-8”)设置请求编码,而非在参数解析后手动转换
3.编码转换应在参数读取阶段完成,而非在验签前的参数处理阶段,否则必然破坏原始数据的字节序列,导致验签失败。
对比:
- 先将