V3接口的下载账单API 的签名以及验签问题?
问题描述:下载账单API 在调用后一直报错 400,检查是签名问题 需求结果是: 能拿到返回的流或者 response.getEntity().getContent()里的json 串 或者byte[]
2022-08-02 15:38:18 |DEBUG| com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials [68] | authorization token=[mchid="公司服务商的mchid",nonce_str="NzWT1hBVAO3krFhTuh7pGZLR9XWx4ORu",timestamp="1659425898",serial_no="公司服务商的的序列号",signature="LRCxDGacoxLQpYNEQaN/pDbuU1VjysywFHN1ZlZstygrZdFnjlYtrApBRPb+dM0jrohAlB3ix5RiKFrbZ4wXlKRrUTWg45aYsS+QdyGkOKwqcN7AKSfqqALluuGuni28Mnx5CFq9DyIVfBM3NfPf6GObzQC/qeJib6LvBI/XukwLRNpC1P5D+ADYrY26FmqM5piOGfrqDFIJ6SfiEKKeagNhNYNJO5voBzPejdzJdNAx99TDKO0r9y/rly2TSUDrUhpO057hxyBilV0oiIpheHPV2t9hmxGIDPoLoXicqfeCPZQI5ctKSWGe4ySZnoHSRB3OPAuGhP8vsvJsHXU/PA=="]
2022-08-02 15:38:18 |ERROR| com.wechat.pay.contrib.apache.httpclient.SignatureExec [95] | 应答的状态码不为200-299。status code[400] request headers[[Authorization: WECHATPAY2-SHA256-RSA2048 mchid="公司服务商的mchid",timestamp="1659425891",nonce_str="8a44047dabe64cf79cc501faa17032b1",serial_no="公司服务商的的序列号",signature="Mpyw0flcxq4rLAr1rlydR3bwhANJMdK0CUrR8Vn02DxtC+QxBtn8gCg68k4ZweFUvE8GFt/DpInEztO4tVMhAqLVmWRC1WyFtGePvbdKtHT9G6LKo5w6glTixVa5CdNQGrQ8h8ye63o1QWnR9BmDD06rIiTaC9CRRlhclQ6wpIUNj6QbdPG4c7CO+a3e/n01WavapoqE75XxyRo7YMgt791XSw9u+gq01DBf9D2yp2Eme+pWReE1LTnQB21j9Ot6nwxWSwawYJeAdwkUG81VgAwoNw4gVLpmhybwXqXgNwt/fEUf7uZ2kVOYUPLoIR0WGYHb2pPAfLjKEbw0k1bs4g==", Authorization: WECHATPAY2-SHA256-RSA2048 mchid="公司服务商的mchid",nonce_str="NzWT1hBVAO3krFhTuh7pGZLR9XWx4ORu",timestamp="1659425898",serial_no="公司服务商的的序列号",signature="LRCxDGacoxLQpYNEQaN/pDbuU1VjysywFHN1ZlZstygrZdFnjlYtrApBRPb+dM0jrohAlB3ix5RiKFrbZ4wXlKRrUTWg45aYsS+QdyGkOKwqcN7AKSfqqALluuGuni28Mnx5CFq9DyIVfBM3NfPf6GObzQC/qeJib6LvBI/XukwLRNpC1P5D+ADYrY26FmqM5piOGfrqDFIJ6SfiEKKeagNhNYNJO5voBzPejdzJdNAx99TDKO0r9y/rly2TSUDrUhpO057hxyBilV0oiIpheHPV2t9hmxGIDPoLoXicqfeCPZQI5ctKSWGe4ySZnoHSRB3OPAuGhP8vsvJsHXU/PA==", Host: api.mch.weixin.qq.com, Connection: Keep-Alive, User-Agent: WechatPay-Apache-HttpClient/0.4.8 (Windows 10/10.0) Java/1.8.0_121, Accept-Encoding: gzip,deflate]]
[图片] 第一个API:调用地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_11.shtml (申请分账账单API ) 调用后返回 结果 如下:(正常返回下载地址) //调用微信API 申请帐单API
WXDimensionResponseVo wxDimensionAPI = wxPay.getWXDimensionAPI(wxDimensionVo);
[图片] 第二个API:调用地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_12.shtml(下载地址) 调用过程如下:(异常出现) //调用微信API 下载文件API
WXBillExcl wXBillExcl = wxPay.getWXDownloadBillingAPI(wxDimensionAPI);
/**
* 请求方式:GET
* param:hash_type 哈希类型
* param:hash_value 哈希值
* param:download_url 下载地址
* author:wzq
* 作用:下载账单API
* @return API返回数据
* @throws Exception
*/
public WXBillExcl getWXDownloadBillingAPI(WXDimensionResponseVo wXDimensionResponseVo) throws WXAPIException, IOException {
InputStream inputStream = downloadV3(URI.create(wXDimensionResponseVo.getDownloadUrl()));
FileOutputStream fos = new FileOutputStream("d:h3.xls");
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) > 0) {
fos.write(b, 0, length);
}
WXBillExcl wxBillExcl = getWXExcl(inputStream);
inputStream.close();
fos.close();
System.out.println("执行完成" + inputStream);
return wxBillExcl;
}
/**
* param:url
* wx v3标准签名
* wzq
* */
public InputStream downloadV3(URI url) throws WXAPIException,IOException {
HttpGet httpGet = null;
try {
httpGet = new HttpGet(url);
httpGet.addHeader("Authorization",schema+" "+ getToken("GET",HttpUrl.parse(url.toString()),""));
CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
return response.getEntity().getContent();
}
} catch (IOException e) {
System.out.println("\n【请求地址:" + url + "\n【异常信息】:" + e.getMessage());
} catch (Exception e) {
System.out.println("\n【请求地址:" + url + "\n【异常信息】:" + e.getMessage());
throw (e instanceof WXAPIException) ? (WXAPIException) e : new WXAPIException(e.getMessage(), e);
} finally {
httpGet.releaseConnection();
}
return null;
}
private final static String schema = "WECHATPAY2-SHA256-RSA2048";
public String getToken(String method, HttpUrl url, String body) {
Long timestamp = System.currentTimeMillis() / 1000;
String nonceStr = UUID.randomUUID().toString().replace("-","");
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = message;
try {
signature = sign(message.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "mchid=\"" + sp_mchid + "\","
+ "timestamp=\"" + timestamp + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "serial_no=\"" + sp_mchSerialNo + "\","
+ "signature=\"" + signature + "\"";
}
public String sign(byte[] message) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(PemUtil.loadPrivateKey(new ByteArrayInputStream(sp_privateKey.getBytes("utf-8"))));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
} catch (SignatureException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 签名的方法
* */
public String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.encodedPath();
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body +"\n";
}