From e7f2378f49079456f8abec5261f64aea3f7cfac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B6=E6=9E=AB?= <954649679@qq.com> Date: Fri, 7 Aug 2020 13:50:07 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20#1639=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=A2=9E=E5=8A=A0v3=E5=9B=BE=E7=89=87=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 实现v3上传图片功能 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml 2. 将接口获取到的证书保存到PayConfig中,v3接口中部分字段是敏感数据,在对这些数据加密时会用到 --- .../wxpay/bean/media/ImageUploadResult.java | 28 +++++++ .../binarywang/wxpay/config/WxPayConfig.java | 23 ++++-- .../wxpay/service/MerchantMediaService.java | 31 ++++++++ .../wxpay/service/WxPayService.java | 11 +++ .../impl/MerchantMediaServiceImpl.java | 44 +++++++++++ .../impl/WxPayServiceApacheHttpImpl.java | 30 ++++++++ .../impl/WxPayServiceJoddHttpImpl.java | 6 ++ .../binarywang/wxpay/v3/Credentials.java | 5 +- .../binarywang/wxpay/v3/SignatureExec.java | 25 +++--- .../wxpay/v3/WechatPayUploadHttpPost.java | 76 +++++++++++++++++++ .../auth/AutoUpdateCertificatesVerifier.java | 16 +++- .../wxpay/v3/auth/CertificatesVerifier.java | 20 +++++ .../binarywang/wxpay/v3/auth/Verifier.java | 5 ++ .../wxpay/v3/auth/WxPayCredentials.java | 26 ++++--- .../impl/MerchantMediaServiceImplTest.java | 54 +++++++++++++ .../src/test/resources/test-config.sample.xml | 8 ++ 16 files changed, 376 insertions(+), 32 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/ImageUploadResult.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WechatPayUploadHttpPost.java create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImplTest.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/ImageUploadResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/ImageUploadResult.java new file mode 100644 index 000000000..8b7f53a2b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/ImageUploadResult.java @@ -0,0 +1,28 @@ +package com.github.binarywang.wxpay.bean.media; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +/** + * 媒体文件上传返回结果对象 + * @author zhouyongshen + */ +@NoArgsConstructor +@Data +public class ImageUploadResult { + + public static ImageUploadResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, ImageUploadResult.class); + } + /** + * 媒体文件标识 Id + * + * 微信返回的媒体文件标识Id。 + * 示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 + * + */ + @SerializedName("media_id") + private String mediaId; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index 6d9bebdc6..4ee1ed707 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -2,10 +2,7 @@ package com.github.binarywang.wxpay.config; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder; -import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier; -import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner; -import com.github.binarywang.wxpay.v3.auth.WxPayCredentials; -import com.github.binarywang.wxpay.v3.auth.WxPayValidator; +import com.github.binarywang.wxpay.v3.auth.*; import com.github.binarywang.wxpay.v3.util.PemUtils; import jodd.util.ResourcesUtil; import lombok.Data; @@ -153,6 +150,12 @@ public class WxPayConfig { private String httpProxyUsername; private String httpProxyPassword; + /** + * v3接口下证书检验对象,通过改对象可以获取到X509Certificate,进一步对敏感信息加密 + * 文档见 https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/min-gan-xin-xi-jia-mi + */ + private Verifier verifier; + /** * 返回所设置的微信支付接口请求地址域名. * @@ -297,14 +300,20 @@ public class WxPayConfig { try { PrivateKey merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); + + AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( + new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), + apiV3Key.getBytes(StandardCharsets.UTF_8)); + + CloseableHttpClient httpClient = WxPayV3HttpClientBuilder.create() .withMerchant(mchId, certSerialNo, merchantPrivateKey) .withWechatpay(Collections.singletonList(PemUtils.loadCertificate(certInputStream))) - .withValidator(new WxPayValidator(new AutoUpdateCertificatesVerifier( - new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), - apiV3Key.getBytes(StandardCharsets.UTF_8)))) + .withValidator(new WxPayValidator(verifier)) .build(); this.apiV3HttpClient = httpClient; + this.verifier=verifier; + return httpClient; } catch (Exception e) { throw new WxPayException("v3请求构造异常!", e); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java new file mode 100644 index 000000000..429ece394 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java @@ -0,0 +1,31 @@ +package com.github.binarywang.wxpay.service; + +import com.github.binarywang.wxpay.bean.media.ImageUploadResult; +import com.github.binarywang.wxpay.exception.WxPayException; + +import java.io.File; +import java.io.IOException; + +/** + *
+ * 微信支付通用媒体接口.
+ * 
+ * + * @author zhouyongshen + */ +public interface MerchantMediaService { + /** + *
+   * 通用接口-图片上传API
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/merchant/media/upload
+   * 
+ * + * @param imageFile 需要上传的图片文件 + * @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 + * @throws WxPayException the wx pay exception + */ + ImageUploadResult imageUploadV3(File imageFile) throws WxPayException, IOException; + + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index b29f50129..565db9c6a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -10,6 +10,7 @@ import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; +import org.apache.http.client.methods.HttpPost; import java.io.File; import java.net.URI; @@ -65,6 +66,16 @@ public interface WxPayService { */ String postV3(String url, String requestStr) throws WxPayException; + /** + * 发送post请求,得到响应字符串. + * + * @param url 请求地址 + * @param httpPost 请求信息 + * @return 返回请求结果字符串 string + * @throws WxPayException the wx pay exception + */ + String postV3(String url, HttpPost httpPost) throws WxPayException; + /** * 发送get V3请求,得到响应字符串. * diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java new file mode 100644 index 000000000..863b706a2 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java @@ -0,0 +1,44 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.media.ImageUploadResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.MerchantMediaService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.WechatPayUploadHttpPost; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * 微信支付-媒体文件上传service + * @author zhouyongshen + */ +@Slf4j +@RequiredArgsConstructor +public class MerchantMediaServiceImpl implements MerchantMediaService { + + private final WxPayService payService; + + @Override + public ImageUploadResult imageUploadV3(File imageFile) throws WxPayException,IOException { + String url = String.format("%s/v3/merchant/media/upload", this.payService.getPayBaseUrl()); + + try (FileInputStream s1 = new FileInputStream(imageFile)) { + String sha256 = DigestUtils.sha256Hex(s1); + try (InputStream s2 = new FileInputStream(imageFile)) { + WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url)) + .withImage(imageFile.getName(), sha256, s2) + .build(); + String result = this.payService.postV3(url, request); + return ImageUploadResult.fromJson(result); + } + } + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java index 951451a1d..7c4f2021a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java @@ -116,6 +116,36 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl { } + @Override + public String postV3(String url, HttpPost httpPost) throws WxPayException { + + httpPost.setConfig(RequestConfig.custom() + .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout()) + .setConnectTimeout(this.getConfig().getHttpConnectionTimeout()) + .setSocketTimeout(this.getConfig().getHttpTimeout()) + .build()); + + CloseableHttpClient httpClient = this.createApiV3HttpClient(); + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + //v3已经改为通过状态码判断200 204 成功 + int statusCode = response.getStatusLine().getStatusCode(); + String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) { + this.log.info("\n【请求地址】:{}\n【响应数据】:{}", url, responseString); + return responseString; + } else { + //有错误提示信息返回 + JsonObject jsonObject = GsonParser.parse(responseString); + throw new WxPayException(jsonObject.get("message").getAsString()); + } + } catch (Exception e) { + this.log.error("\n【请求地址】:{}\n【异常信息】:{}", url, e.getMessage()); + throw new WxPayException(e.getMessage(), e); + } finally { + httpPost.releaseConnection(); + } + } + @Override public String getV3(URI url) throws WxPayException { CloseableHttpClient httpClient = this.createApiV3HttpClient(); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java index b37160f90..91292e810 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java @@ -16,6 +16,7 @@ import jodd.http.ProxyInfo.ProxyType; import jodd.http.net.SSLSocketHttpConnectionProvider; import jodd.http.net.SocketHttpConnectionProvider; import jodd.util.Base64; +import org.apache.http.client.methods.HttpPost; /** * 微信支付请求实现类,jodd-http实现. @@ -65,6 +66,11 @@ public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl { return null; } + @Override + public String postV3(String url, HttpPost httpPost) throws WxPayException { + return null; + } + @Override public String getV3(URI url) throws WxPayException { return null; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/Credentials.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/Credentials.java index d5102d1fa..495e883f5 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/Credentials.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/Credentials.java @@ -1,11 +1,12 @@ package com.github.binarywang.wxpay.v3; import java.io.IOException; -import org.apache.http.client.methods.HttpUriRequest; + +import org.apache.http.client.methods.HttpRequestWrapper; public interface Credentials { String getSchema(); - String getToken(HttpUriRequest request) throws IOException; + String getToken(HttpRequestWrapper request) throws IOException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java index a28dfdcd6..2345e3c68 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java @@ -2,6 +2,7 @@ package com.github.binarywang.wxpay.v3; import java.io.IOException; import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; @@ -12,6 +13,7 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.execchain.ClientExecChain; import org.apache.http.util.EntityUtils; @@ -43,11 +45,11 @@ public class SignatureExec implements ClientExecChain { } } - protected void convertToRepeatableRequestEntity(HttpUriRequest request) throws IOException { - if (request instanceof HttpEntityEnclosingRequestBase) { - HttpEntity entity = ((HttpEntityEnclosingRequestBase) request).getEntity(); - if (entity != null && !entity.isRepeatable()) { - ((HttpEntityEnclosingRequestBase) request).setEntity(newRepeatableEntity(entity)); + protected void convertToRepeatableRequestEntity(HttpRequestWrapper request) throws IOException { + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + if (entity != null) { + ((HttpEntityEnclosingRequest) request).setEntity(new BufferedHttpEntity(entity)); } } } @@ -64,15 +66,16 @@ public class SignatureExec implements ClientExecChain { private CloseableHttpResponse executeWithSignature(HttpRoute route, HttpRequestWrapper request, HttpClientContext context, HttpExecutionAware execAware) throws IOException, HttpException { - HttpUriRequest newRequest = RequestBuilder.copy(request.getOriginal()).build(); - convertToRepeatableRequestEntity(newRequest); + // 上传类不需要消耗两次故不做转换 + if (!(request.getOriginal() instanceof WechatPayUploadHttpPost)) { + convertToRepeatableRequestEntity(request); + } // 添加认证信息 - newRequest.addHeader("Authorization", - credentials.getSchema() + " " + credentials.getToken(newRequest)); + request.addHeader("Authorization", + credentials.getSchema() + " " + credentials.getToken(request)); // 执行 - CloseableHttpResponse response = mainExec.execute( - route, HttpRequestWrapper.wrap(newRequest), context, execAware); + CloseableHttpResponse response = mainExec.execute(route, request, context, execAware); // 对成功应答验签 StatusLine statusLine = response.getStatusLine(); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WechatPayUploadHttpPost.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WechatPayUploadHttpPost.java new file mode 100644 index 000000000..df0ee4e2f --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WechatPayUploadHttpPost.java @@ -0,0 +1,76 @@ +package com.github.binarywang.wxpay.v3; + +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; + +import java.io.InputStream; +import java.net.URI; +import java.net.URLConnection; + +public class WechatPayUploadHttpPost extends HttpPost { + + private String meta; + + private WechatPayUploadHttpPost(URI uri, String meta) { + super(uri); + + this.meta = meta; + } + + public String getMeta() { + return meta; + } + + public static class Builder { + + private String fileName; + private String fileSha256; + private InputStream fileInputStream; + private ContentType fileContentType; + private URI uri; + + public Builder(URI uri) { + this.uri = uri; + } + + public Builder withImage(String fileName, String fileSha256, InputStream inputStream) { + this.fileName = fileName; + this.fileSha256 = fileSha256; + this.fileInputStream = inputStream; + + String mimeType = URLConnection.guessContentTypeFromName(fileName); + if (mimeType == null) { + // guess this is a video uploading + this.fileContentType = ContentType.APPLICATION_OCTET_STREAM; + } else { + this.fileContentType = ContentType.create(mimeType); + } + return this; + } + + public WechatPayUploadHttpPost build() { + if (fileName == null || fileSha256 == null || fileInputStream == null) { + throw new IllegalArgumentException("缺少待上传图片文件信息"); + } + + if (uri == null) { + throw new IllegalArgumentException("缺少上传图片接口URL"); + } + + String meta = String.format("{\"filename\":\"%s\",\"sha256\":\"%s\"}", fileName, fileSha256); + WechatPayUploadHttpPost request = new WechatPayUploadHttpPost(uri, meta); + + MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create(); + entityBuilder.setMode(HttpMultipartMode.RFC6532) + .addBinaryBody("file", fileInputStream, fileContentType, fileName) + .addTextBody("meta", meta, ContentType.APPLICATION_JSON); + + request.setEntity(entityBuilder.build()); + request.addHeader("Accept", ContentType.APPLICATION_JSON.toString()); + + return request; + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java index db656f4c9..a49010814 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java @@ -100,6 +100,14 @@ public class AutoUpdateCertificatesVerifier implements Verifier { @Override public boolean verify(String serialNumber, byte[] message, String signature) { + checkAndAutoUpdateCert(); + return verifier.verify(serialNumber, message, signature); + } + + /** + * 检查证书是否在有效期内,如果不在有效期内则进行更新 + */ + private void checkAndAutoUpdateCert() { if (instant == null || Minutes.minutesBetween(instant, Instant.now()).getMinutes() >= minutesInterval) { if (lock.tryLock()) { try { @@ -113,7 +121,6 @@ public class AutoUpdateCertificatesVerifier implements Verifier { } } } - return verifier.verify(serialNumber, message, signature); } private void autoUpdateCert() throws IOException, GeneralSecurityException { @@ -179,4 +186,11 @@ public class AutoUpdateCertificatesVerifier implements Verifier { return newCertList; } + + @Override + public X509Certificate getValidCertificate() { + checkAndAutoUpdateCert(); + return verifier.getValidCertificate(); + } + } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java index 9853cf2ee..7239d9e64 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java @@ -5,10 +5,13 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.HashMap; import java.util.List; +import java.util.NoSuchElementException; public class CertificatesVerifier implements Verifier { private final HashMap certificates = new HashMap<>(); @@ -40,4 +43,21 @@ public class CertificatesVerifier implements Verifier { BigInteger val = new BigInteger(serialNumber, 16); return certificates.containsKey(val) && verify(certificates.get(val), message, signature); } + + + @Override + public X509Certificate getValidCertificate() { + for (X509Certificate x509Cert : certificates.values()) { + try { + x509Cert.checkValidity(); + + return x509Cert; + } catch (CertificateExpiredException | CertificateNotYetValidException e) { + continue; + } + } + + throw new NoSuchElementException("没有有效的微信支付平台证书"); + } + } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java index ed591a4ef..49f92e2f5 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java @@ -1,5 +1,10 @@ package com.github.binarywang.wxpay.v3.auth; +import java.security.cert.X509Certificate; + public interface Verifier { boolean verify(String serialNumber, byte[] message, String signature); + + + X509Certificate getValidCertificate(); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayCredentials.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayCredentials.java index 9fca14e64..80eea8f68 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayCredentials.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayCredentials.java @@ -1,16 +1,18 @@ package com.github.binarywang.wxpay.v3.auth; +import com.github.binarywang.wxpay.v3.Credentials; +import com.github.binarywang.wxpay.v3.WechatPayUploadHttpPost; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.client.methods.HttpRequestWrapper; +import org.apache.http.util.EntityUtils; + import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.security.SecureRandom; -import com.github.binarywang.wxpay.v3.Credentials; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.util.EntityUtils; - @Slf4j public class WxPayCredentials implements Credentials { private static final String SYMBOLS = @@ -46,14 +48,14 @@ public class WxPayCredentials implements Credentials { } @Override - public final String getToken(HttpUriRequest request) throws IOException { + public final String getToken(HttpRequestWrapper request) throws IOException { String nonceStr = generateNonceStr(); long timestamp = generateTimestamp(); String message = buildMessage(nonceStr, timestamp, request); log.debug("authorization message=[{}]", message); - Signer.SignatureResult signature = signer.sign(message.getBytes("utf-8")); + Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8)); String token = "mchid=\"" + getMerchantId() + "\"," + "nonce_str=\"" + nonceStr + "\"," @@ -65,7 +67,7 @@ public class WxPayCredentials implements Credentials { return token; } - protected final String buildMessage(String nonce, long timestamp, HttpUriRequest request) + protected final String buildMessage(String nonce, long timestamp, HttpRequestWrapper request) throws IOException { URI uri = request.getURI(); String canonicalUrl = uri.getRawPath(); @@ -75,8 +77,10 @@ public class WxPayCredentials implements Credentials { String body = ""; // PATCH,POST,PUT - if (request instanceof HttpEntityEnclosingRequestBase) { - body = EntityUtils.toString(((HttpEntityEnclosingRequestBase) request).getEntity()); + if (request.getOriginal() instanceof WechatPayUploadHttpPost) { + body = ((WechatPayUploadHttpPost) request.getOriginal()).getMeta(); + } else if (request instanceof HttpEntityEnclosingRequest) { + body = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity()); } return request.getRequestLine().getMethod() + "\n" diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImplTest.java new file mode 100644 index 000000000..c8dd069b4 --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImplTest.java @@ -0,0 +1,54 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.media.ImageUploadResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.MerchantMediaService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.testbase.ApiTestModule; +import com.google.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; + +/** + *
+ *  媒体文件上传测试类
+ * 
+ * + * @author zhouyongshen + */ +@Slf4j +@Test +@Guice(modules = ApiTestModule.class) +public class MerchantMediaServiceImplTest { + + @Inject + private WxPayService wxPayService; + + @Test + public void testImageUploadV3() throws WxPayException, IOException { + + MerchantMediaService merchantMediaService=new MerchantMediaServiceImpl(wxPayService); + + String filePath="你的图片文件的路径地址"; +// String filePath="WxJava/images/banners/wiki.jpg"; + + File file=new File(filePath); + + ImageUploadResult imageUploadResult = merchantMediaService.imageUploadV3(file); + String mediaId = imageUploadResult.getMediaId(); + + log.info("mediaId1:[{}]",mediaId); + + File file2=new File(filePath); + + ImageUploadResult imageUploadResult2 = merchantMediaService.imageUploadV3(file2); + String mediaId2 = imageUploadResult2.getMediaId(); + + log.info("mediaId2:[{}]",mediaId2); + + } +} diff --git a/weixin-java-pay/src/test/resources/test-config.sample.xml b/weixin-java-pay/src/test/resources/test-config.sample.xml index 1e64cbe40..25ec4be05 100644 --- a/weixin-java-pay/src/test/resources/test-config.sample.xml +++ b/weixin-java-pay/src/test/resources/test-config.sample.xml @@ -10,4 +10,12 @@ --> 商户平台的证书文件地址 某个openId + +