让http每次连接API时,都必须附上私钥和证书。
@Configuration
public class SSLRestTemplateConfig {
@Bean("sslRestTemplate")
public RestTemplate restTemplate() throws Exception {
return new RestTemplate(httpRequestFactory());
}
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
public ClientHttpRequestFactory httpRequestFactory() throws Exception {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
public HttpClient httpClient() throws Exception {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https",buildSSLSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(1000); //设置整个连接池最大连接数 根据自己的场景决定
connectionManager.setDefaultMaxPerRoute(500); //路由是对maxTotal的细分,并发数
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(10000) //服务器返回数据(response)的时间,超过该时间抛出read timeout
.setConnectTimeout(10000)//连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
.setConnectionRequestTimeout(8000)//从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true)) // 重试次数
.setSSLSocketFactory(buildSSLSocketFactory())
.build();
}
private SSLConnectionSocketFactory buildSSLSocketFactory() throws Exception {
SSLContext sslContext;
sslContext = SSLContexts.custom().build();
sslContext.init(new KeyManager[]{new MyX509KeyManager("ssl/xxx.key", "ssl/xxx.pem")
}, new TrustManager[]{new MyX509TrustManager()}, null);
return new SSLConnectionSocketFactory(sslContext, (urlHostName, session) -> true);
}
}
public class MyX509KeyManager implements X509KeyManager {
PrivateKey rsa;
X509Certificate pkcert;
public MyX509KeyManager(String keyFile, String pemFile) throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException, CertificateException {
InputStream inputStream = new ClassPathResource(keyFile).getInputStream();
String privateKey = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
//KeyStore用于存放证书,创建对象时 指定交换数字证书的加密标准
privateKey = privateKey.replace("-----BEGIN RSA PRIVATE KEY-----", "")
.replace("-----END RSA PRIVATE KEY-----", "")
.replace("\n", "")
.trim();
byte[] decode = Base.getDecoder().decode(privateKey);
rsa = KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(decode));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
pkcert = (X509Certificate) cf.generateCertificate(
new ClassPathResource(pemFile).getInputStream()
);
}
@Override
public String[] getClientAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
return "00";
}
@Override
public String[] getServerAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
return null;
}
@Override
public X509Certificate[] getCertificateChain(String s) {
return new X509Certificate[]{
pkcert
};
}
@Override
public PrivateKey getPrivateKey(String s) {
return rsa;
}
}