linwe
2024-09-03 764d883b5ea3bdc06abbec548b6df0511e567978
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package org.springblade.common.config;
 
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
 
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
 
 
@Configuration
@ConfigurationProperties(prefix = "wxpay") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {
 
    // 商户号
    private String mchId;
 
    // 商户API证书序列号
    private String mchSerialNo;
 
    // 商户私钥文件
    private String privateKeyPath;
 
    private String privateCertPath;
 
    // APIv3密钥
    private String apiV3Key;
 
    // APPID
    private String appid;
 
    // 微信服务器地址
    private String domain;
 
    // 接收结果通知地址
    private String notifyDomain;
 
    // APIv2密钥
    private String partnerKey;
 
    /**
     * 获取商户的私钥文件
     *
     * @param filename
     * @return
     */
    private PrivateKey getPrivateKey(String filename) {
 
        try {
            // FileInputStream fileInputStream = new FileInputStream(filename);
            // log.info("文件内容:" + fileInputStream);
            return PemUtil.loadPrivateKey(getFileInputStream(filename));
        } catch (Exception e) {
            log.info("私钥文件不存在", e);
            throw new RuntimeException("私钥文件不存在", e);
        }
    }
 
 
    /**
     * 获取商户的文件
     *
     * @param filename
     * @return
     */
    public static FileInputStream getFileInputStream(String filename) {
 
        try {
            FileInputStream fileInputStream = new FileInputStream(filename);
            return fileInputStream;
        } catch (Exception e) {
            log.info("读取文件不存在", e);
            throw new RuntimeException("读取文件不存在", e);
        }
    }
 
    /**
     * 获取商户的文件
     *
     * @return
     */
    // @Bean
    // public KeyStore keyStore() {
    //     try {
    //         InputStream certStream = WxPayConfig.class.getClassLoader().getResourceAsStream(privateCertPath);
    //         KeyStore ks = KeyStore.getInstance("PKCS12");
    //         ks.load(certStream, mchId.toCharArray());
    //         return ks;
    //     } catch (Exception e) {
    //         log.info("读取文件不存在", e);
    //         throw new RuntimeException("读取文件不存在", e);
    //     }
    // }
 
 
    /**
     * 获取签名验证器
     *
     * @return
     */
//    @Bean
    public ScheduledUpdateCertificatesVerifier getVerifier() {
 
        log.info("获取签名验证器");
 
        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
 
        //私钥签名对象
        PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);
 
        //身份认证对象
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
 
        // 使用定时更新的签名验证器,不需要传入证书
        ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
            wechatPay2Credentials,
            apiV3Key.getBytes(StandardCharsets.UTF_8));
 
        return verifier;
    }
 
 
    /**
     * 获取http请求对象
     *
     * @param verifier
     * @return
     */
//    @Bean(name = "wxPayClient")
    public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier) {
 
        log.info("获取httpClient");
 
        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
 
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
            .withMerchant(mchId, mchSerialNo, privateKey)
            .withValidator(new WechatPay2Validator(verifier));
        // ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
 
        // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
        CloseableHttpClient httpClient = builder.build();
 
        return httpClient;
    }
 
    /**
     * 获取HttpClient,无需进行应答签名验证,跳过验签的流程
     */
//    @Bean(name = "wxPayNoSignClient")
    public CloseableHttpClient getWxPayNoSignClient() {
 
        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
 
        //用于构造HttpClient
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
            //设置商户信息
            .withMerchant(mchId, mchSerialNo, privateKey)
            //无需进行签名验证、通过withValidator((response) -> true)实现
            .withValidator((response) -> true);
 
        // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
        CloseableHttpClient httpClient = builder.build();
 
        log.info("== getWxPayNoSignClient END ==");
 
        return httpClient;
    }
 
 
}