1、沙箱环境需要调用接口生成一个沙箱的key,替换原来的key才行
代码如下
/**
* 获取沙箱的key(沙箱测试时需要获取沙箱key)
* @return
*/
public String getSandboxSignKey() {
try {
MyWXPayConfig config = getConfig();
WXPay wxPay = getWXPay();
Map<String, String> params = new HashMap<>();
params.put("mch_id", config.getMchID());
params.put("nonce_str", WXPayUtil.generateNonceStr());
params.put("sign", WXPayUtil.generateSignature(params, config.getKey()));
String strXML = wxPay.requestWithoutCert("/sandboxnew/pay/getsignkey",
params, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs());
if (StringUtils.isBlank(strXML)) {
return null;
}
Map<String, String> response = WXPayUtil.xmlToMap(strXML);
logger.info("微信生成沙箱签名接口调用成功:" + response);
if ("SUCCESS".equals(response.get("return_code"))) {
return response.get("sandbox_signkey");
}
return null;
} catch (Exception e) {
logger.error("微信生成沙箱签名接口调用失败", e);
return null;
}
}
2、沙箱环境接口请求的url都带上/sandboxnew
例如,付款码支付URL:https://api.mch.weixin.qq.com/pay/micropay
变更为:https://api.mch.weixin.qq.com/sandboxnew/pay/micropay。
3、沙箱生成二维码后,返回的code_url是无效的,沙箱环境是忽略掉用户扫码支付这个过程(这个问题坑了我很久,官方文档细节都不说明的)
文章:https://bbs.csdn.net/topics/392439936?page=1
4、沙箱环境需要跟着官方下载的测试用例去输入金额,否则会报错说金额不对
5、支付回调校验签名问题
签名算法不一致:https://blog.csdn.net/aoeace/article/details/84914445
WXPay的构造函数中,默认把非沙箱环境的签名加密方法设为HMACSHA256
public WXPay(WXPayConfig config, String notifyUrl, boolean autoReport, boolean useSandbox) throws Exception {
this.config = config;
this.notifyUrl = notifyUrl;
this.autoReport = autoReport;
this.useSandbox = useSandbox;
if (useSandbox) {
this.signType = SignType.MD5;
} else {
this.signType = SignType.HMACSHA256;
}
this.wxPayRequest = new WXPayRequest(config);
}
如果使用如下方法校验支付回调签名,由于微信没有返回sign_type的xml标签,导致默认会使用md5去生成签名做比对。所以使用该方法做签名校验,会一直返回false校验不通过。建议使用isResponseSignatureValid()即可
public boolean isPayResultNotifySignatureValid(Map<String, String> reqData) throws Exception {
String signTypeInData = (String)reqData.get("sign_type");
SignType signType;
if (signTypeInData == null) {
signType = SignType.MD5;
} else {
signTypeInData = signTypeInData.trim();
if (signTypeInData.length() == 0) {
signType = SignType.MD5;
} else if ("MD5".equals(signTypeInData)) {
signType = SignType.MD5;
} else {
if (!"HMAC-SHA256".equals(signTypeInData)) {
throw new Exception(String.format("Unsupported sign_type: %s", signTypeInData));
}
signType = SignType.HMACSHA256;
}
}
校验签名,因为支付回调的返回值默认没有
6、退款问题
(1)要下载api证书,并且加载到项目中,微信的sdk中。继承WXPayConfig后,可以重写getCertStream()方法,指定加载证书
@Override
public InputStream getCertStream() {
//我是放在项目中
Resource resource = new ClassPathResource("cert/apiclient_cert.p12");
File file = null;
try {
file = resource.getFile();
FileInputStream instream = new FileInputStream(file);
return instream;
} catch (IOException e) {
e.printStackTrace();
throw new Exception("找不到证书文件", e);
}
}
7、退款回调问题
(1)退款回调的req_info需要进行解密
key是取之前生成下订单之类使用的密钥key
这里做AES-256-ECB解析时要注意会报错
java.security.InvalidKeyException: Illegal key size
参考文章:https://www.cnblogs.com/yaks/p/5608358.html
JAVA运行环境默认不允许256位密钥的AES加解密,解决方法就是修改策略文件
在官方网站下载JCE无限制权限策略文件
JDK7版本JCE下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8版本JCE下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
- 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
- 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
- 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
实践:
以JDK8为例,系统为WIN10,替换上述security文件夹下\policy\limited文件夹和\policy\unlimited文件夹里面的local_policy.jar和US_export_policy.jar这两个文件。
若是在服务器上,则只有在security目录下有local_policy.jar和US_export_policy.jar,替换即可
//参考微信的解密说明:参数一是base64解密过的密串,参数二是md5加密后转小写
private String aes256Decode(byte[] base64Data,byte[] keyByte) throws Exception {
String ALGORITHM = "AES";
String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";
SecretKeySpec key = new SecretKeySpec(keyByte, ALGORITHM);
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING, "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(base64Data));
}