1. 添加HttpsClientRequestFactory工具类
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;
/**
* TLS的三个作用:
* (1)身份认证
* 通过证书认证来确认对方的身份,防止中间人攻击
* (2)数据私密性
* 使用对称性密钥加密传输的数据,由于密钥只有客户端/服务端有,其他人无法窥探。
* (3)数据完整性
* 使用摘要算法对报文进行计算,收到消息后校验该值防止数据被篡改或丢失。
*
* 使用RestTemplate进行HTTPS请求访问:
* private static RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());
*
*/
public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
try {
if (!(connection instanceof HttpsURLConnection)) {
throw new RuntimeException("An instance of HttpsURLConnection is expected");
}
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// 这里修改TLS版本会被下面的覆盖
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));
httpsConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
super.prepareConnection(httpsConnection, httpMethod);
} catch (Exception e) {
e.printStackTrace();
}
}
private static class MyCustomSSLSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
// 返回默认启用的密码套件。除非一个列表启用,对SSL连接的握手会使用这些密码套件。
// 这些默认的服务的最低质量要求保密保护和服务器身份验证
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
// 返回的密码套件可用于SSL连接启用的名字
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket(final Socket socket, final String host, final int port,
final boolean autoClose) throws IOException {
final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final String host, final int port) throws IOException {
final Socket underlyingSocket = delegate.createSocket(host, port);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final String host, final int port, final InetAddress localAddress,
final int localPort) throws
IOException {
final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final InetAddress host, final int port) throws IOException {
final Socket underlyingSocket = delegate.createSocket(host, port);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
final int localPort) throws
IOException {
final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
return overrideProtocol(underlyingSocket);
}
private Socket overrideProtocol(final Socket socket) {
if (!(socket instanceof SSLSocket)) {
throw new RuntimeException("An instance of SSLSocket is expected");
}
// 连接调用要升级TLS版本用这个,当支持的是列表时,能够与不同版本的客户端进行通信,在握手期间,TLS会选择两者都支持的最高的版本
//((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2"});
((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"});
return socket;
}
}
}
注意:服务端TLS版本要和客户端工具类中定义的一致,
当支持的是列表时,能够与不同版本的客户端进行通信,在握手期间,TLS会选择两者都支持的最高的版本
2. 修改RestTemplate
@Bean
@Primary
public RestTemplate getRestTemplate() {
HttpsClientRequestFactory httpsClientRequestFactory = new HttpsClientRequestFactory();
httpsClientRequestFactory.setConnectTimeout(3600);
httpsClientRequestFactory.setReadTimeout(50 * 1000);
RestTemplate restTemplate = new RestTemplate(httpsClientRequestFactory);
restTemplate.setInterceptors(.....);
return restTemplate;
}
3、访问https,抛出的异常
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure解决方案
方法升级JDK版本
4. 全局设置TLS版本
全局设置优先级 > 代码里面的设置
-Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2文章来源:https://www.toymoban.com/news/detail-429807.html
5. 单独设置信任SSL的template
@Bean(name = "sslRestTemplate")
public RestTemplate sslRestTemplate() {
RestTemplate restTemplate = null;
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
try {
// 设置SSL
TrustStrategy trustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContexts =
SSLContexts.custom().loadTrustMaterial(null, trustStrategy).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContexts, new String[]{"TLSv1.2"}, null
, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
factory.setHttpClient(httpClient);
restTemplate = new RestTemplate(factory);
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
LOGGER.error("exception : ", e);
}
return restTemplate;
}
参考文章: 使用RestTemplate访问https实现SSL请求操作_java_脚本之家文章来源地址https://www.toymoban.com/news/detail-429807.html
到了这里,关于使用RestTemplate访问https实现SSL请求操作,设置TLS版本的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!