1
1
package com .wechat .pay .java .core .certificate ;
2
2
3
- import static com .wechat .pay .java .core .cipher .Constant .HEX ;
4
-
5
- import com .wechat .pay .java .core .auth .Validator ;
6
- import com .wechat .pay .java .core .auth .WechatPay2Validator ;
7
3
import com .wechat .pay .java .core .certificate .model .Data ;
8
4
import com .wechat .pay .java .core .certificate .model .DownloadCertificateResponse ;
9
5
import com .wechat .pay .java .core .certificate .model .EncryptCertificate ;
10
6
import com .wechat .pay .java .core .cipher .AeadCipher ;
11
- import com .wechat .pay .java .core .exception .ValidationException ;
12
7
import com .wechat .pay .java .core .http .Constant ;
13
8
import com .wechat .pay .java .core .http .HttpClient ;
14
9
import com .wechat .pay .java .core .http .HttpMethod ;
15
10
import com .wechat .pay .java .core .http .HttpRequest ;
16
11
import com .wechat .pay .java .core .http .HttpResponse ;
17
- import com .wechat .pay .java .core .http .JsonResponseBody ;
18
12
import com .wechat .pay .java .core .http .MediaType ;
13
+ import com .wechat .pay .java .core .util .PemUtil ;
19
14
import java .nio .charset .StandardCharsets ;
20
15
import java .security .cert .X509Certificate ;
21
- import java .util .ArrayList ;
22
16
import java .util .Base64 ;
23
17
import java .util .HashMap ;
24
18
import java .util .List ;
30
24
/** 自动更新平台证书提供器抽象类 */
31
25
public abstract class AbstractAutoCertificateProvider implements CertificateProvider {
32
26
private static final Logger log = LoggerFactory .getLogger (AbstractAutoCertificateProvider .class );
33
- protected static final int UPDATE_INTERVAL_MINUTE = 60 ; // 定时更新时间,1小时
27
+ protected static final int UPDATE_INTERVAL_MINUTE = 60 ; // 定时更新时间,60分钟,即1小时
34
28
protected final SafeSingleScheduleExecutor executor =
35
29
SafeSingleScheduleExecutor .getInstance (); // 安全的单线程定时执行器实例
36
- protected String requestUrl ; // 请求URl
30
+
37
31
protected String merchantId ; // 商户号
38
32
39
33
protected CertificateHandler certificateHandler ; // 证书处理器
40
34
protected AeadCipher aeadCipher ; // 解密平台证书的aeadCipher;
41
35
protected HttpClient httpClient ; // 下载平台证书的httpClient
42
36
private final HttpRequest httpRequest ; // http请求
43
- private Validator validator ; // 验证器
44
37
45
- private int updateTime ; // 自动更新次数
38
+ private int updateCount ; // 自动更新次数
39
+ private int succeedCount ; // 成功次数
46
40
private final Map <String , Map <String , X509Certificate >> certificateMap ; // 证书map
47
41
48
42
protected AbstractAutoCertificateProvider (
@@ -52,6 +46,24 @@ protected AbstractAutoCertificateProvider(
52
46
HttpClient httpClient ,
53
47
String merchantId ,
54
48
Map <String , Map <String , X509Certificate >> wechatPayCertificateMap ) {
49
+ this (
50
+ requestUrl ,
51
+ certificateHandler ,
52
+ aeadCipher ,
53
+ httpClient ,
54
+ merchantId ,
55
+ wechatPayCertificateMap ,
56
+ UPDATE_INTERVAL_MINUTE * 60 );
57
+ }
58
+
59
+ protected AbstractAutoCertificateProvider (
60
+ String requestUrl ,
61
+ CertificateHandler certificateHandler ,
62
+ AeadCipher aeadCipher ,
63
+ HttpClient httpClient ,
64
+ String merchantId ,
65
+ Map <String , Map <String , X509Certificate >> wechatPayCertificateMap ,
66
+ int updateInterval ) {
55
67
this .merchantId = merchantId ;
56
68
synchronized (AbstractAutoCertificateProvider .class ) {
57
69
if (!wechatPayCertificateMap .containsKey (merchantId )) {
@@ -61,7 +73,7 @@ protected AbstractAutoCertificateProvider(
61
73
"The corresponding provider for the merchant already exists." );
62
74
}
63
75
}
64
- this . requestUrl = requestUrl ;
76
+
65
77
this .certificateHandler = certificateHandler ;
66
78
this .aeadCipher = aeadCipher ;
67
79
this .httpClient = httpClient ;
@@ -73,42 +85,49 @@ protected AbstractAutoCertificateProvider(
73
85
.addHeader (Constant .ACCEPT , " */*" )
74
86
.addHeader (Constant .CONTENT_TYPE , MediaType .APPLICATION_JSON .getValue ())
75
87
.build ();
88
+ // 下载证书,如果失败会抛出异常
76
89
downloadAndUpdate (wechatPayCertificateMap );
90
+
77
91
Runnable runnable =
78
92
() -> {
79
93
log .info (
80
- "Begin update Certificates.merchantId:{},total updates:{}" , merchantId , updateTime );
81
- downloadAndUpdate (wechatPayCertificateMap );
94
+ "Begin update Certificates.merchantId:{},total updates:{}" , merchantId , updateCount );
95
+ try {
96
+ updateCount ++;
97
+ downloadAndUpdate (wechatPayCertificateMap );
98
+ succeedCount ++;
99
+ } catch (Exception e ) {
100
+ // 已经有证书了,失败暂时忽略
101
+ log .error ("Download and update WechatPay certificates failed." , e );
102
+ }
103
+
82
104
log .info (
83
- "Finish update Certificates.merchantId:{},total updates:{}" , merchantId , updateTime );
105
+ "Finish update Certificates.merchantId:{},total updates:{}, succeed updates:{}" ,
106
+ merchantId ,
107
+ updateCount ,
108
+ succeedCount );
84
109
};
85
- executor .scheduleAtFixedRate (
86
- runnable , UPDATE_INTERVAL_MINUTE , UPDATE_INTERVAL_MINUTE , TimeUnit .MINUTES );
110
+ executor .scheduleAtFixedRate (runnable , updateInterval , updateInterval , TimeUnit .SECONDS );
87
111
}
88
112
89
- /** 下载和更新证书 */
113
+ /**
114
+ * 下载并更新证书
115
+ *
116
+ * @param wechatPayCertificateMap 存放多商户对应证书的Map
117
+ */
90
118
protected void downloadAndUpdate (
91
119
Map <String , Map <String , X509Certificate >> wechatPayCertificateMap ) {
92
- try {
93
- HttpResponse <DownloadCertificateResponse > httpResponse = downloadCertificate (httpClient );
94
- validateCertificate (httpResponse );
95
- updateCertificate (httpResponse , wechatPayCertificateMap );
96
- validator =
97
- new WechatPay2Validator (
98
- certificateHandler .generateVerifier (
99
- new ArrayList <>(wechatPayCertificateMap .get (merchantId ).values ())));
100
- updateTime ++;
101
- } catch (Exception e ) {
102
- if (validator == null ) {
103
- throw e ;
104
- }
105
- log .error ("Download and update WechatPay certificates failed." , e );
106
- }
120
+ HttpResponse <DownloadCertificateResponse > httpResponse = downloadCertificate (httpClient );
121
+
122
+ Map <String , X509Certificate > downloaded = decryptCertificate (httpResponse );
123
+ validateCertificate (downloaded );
124
+ wechatPayCertificateMap .put (merchantId , downloaded );
107
125
}
108
126
109
127
/**
110
128
* 下载证书
111
129
*
130
+ * @param httpClient 下载使用的HttpClient
112
131
* @return httpResponse
113
132
*/
114
133
protected HttpResponse <DownloadCertificateResponse > downloadCertificate (HttpClient httpClient ) {
@@ -117,30 +136,18 @@ protected HttpResponse<DownloadCertificateResponse> downloadCertificate(HttpClie
117
136
return httpResponse ;
118
137
}
119
138
120
- /**
121
- * 校验下载证书
122
- *
123
- * @param httpResponse httpResponse
124
- */
125
- protected void validateCertificate (HttpResponse <DownloadCertificateResponse > httpResponse ) {
126
- JsonResponseBody responseBody = (JsonResponseBody ) (httpResponse .getBody ());
127
- if (validator != null
128
- && !validator .validate (httpResponse .getHeaders (), responseBody .getBody ())) {
129
- throw new ValidationException (
130
- String .format (
131
- "Validate response failed,the WechatPay signature is incorrect.responseHeader[%s]\t responseBody[%.1024s]" ,
132
- httpResponse .getHeaders (), httpResponse .getServiceResponse ()));
133
- }
139
+ protected void validateCertificate (Map <String , X509Certificate > certificates ) {
140
+ certificates .forEach ((serialNo , cert ) -> certificateHandler .validateCertPath (cert ));
134
141
}
135
142
136
143
/**
137
- * 更新证书
144
+ * 从应答报文中解密证书
138
145
*
139
146
* @param httpResponse httpResponse
147
+ * @return 应答报文解密后,生成X.509证书对象的Map
140
148
*/
141
- protected void updateCertificate (
142
- HttpResponse <DownloadCertificateResponse > httpResponse ,
143
- Map <String , Map <String , X509Certificate >> wechatPayCertificateMap ) {
149
+ protected Map <String , X509Certificate > decryptCertificate (
150
+ HttpResponse <DownloadCertificateResponse > httpResponse ) {
144
151
List <Data > dataList = httpResponse .getServiceResponse ().getData ();
145
152
Map <String , X509Certificate > downloadCertMap = new HashMap <>();
146
153
for (Data data : dataList ) {
@@ -152,9 +159,9 @@ protected void updateCertificate(
152
159
encryptCertificate .getNonce ().getBytes (StandardCharsets .UTF_8 ),
153
160
Base64 .getDecoder ().decode (encryptCertificate .getCiphertext ()));
154
161
certificate = certificateHandler .generateCertificate (decryptCertificate );
155
- downloadCertMap .put (certificate .getSerialNumber (). toString ( HEX ). toUpperCase ( ), certificate );
162
+ downloadCertMap .put (PemUtil .getSerialNumber (certificate ), certificate );
156
163
}
157
- wechatPayCertificateMap . put ( merchantId , downloadCertMap ) ;
164
+ return downloadCertMap ;
158
165
}
159
166
160
167
public X509Certificate getAvailableCertificate (Map <String , X509Certificate > certificateMap ) {
0 commit comments