通过主机验证,使用Spring RestTemplate实现HTTPS Rest api
我读过很多关于这个问题的文章,我认为我已经找到了最简单的解决方法(这里的最后一个代码示例:),但它不起作用 以下是在主机名验证关闭(以及代理设置)的情况下声明RestTemplate的方式: 下面是创建我的POST请求的代码:通过主机验证,使用Spring RestTemplate实现HTTPS Rest api,spring,rest,ssl,ssl-certificate,resttemplate,Spring,Rest,Ssl,Ssl Certificate,Resttemplate,我读过很多关于这个问题的文章,我认为我已经找到了最简单的解决方法(这里的最后一个代码示例:),但它不起作用 以下是在主机名验证关闭(以及代理设置)的情况下声明RestTemplate的方式: 下面是创建我的POST请求的代码: LoginResponse loginResponse = restTemplate.postForObject("https://interflex.svc.suezsmartsolutions.com/path/to/my/api", loginRequest,
LoginResponse loginResponse = restTemplate.postForObject("https://interflex.svc.suezsmartsolutions.com/path/to/my/api", loginRequest, LoginResponse.class);
下面是我得到的例外(就像我没有关闭主机名验证程序一样):
有人能帮我摆脱这个例外吗
此外,我也不知道为什么会出现此异常,因为用于生成站点证书(VeriSign)的根CA存在于我的信任库(cacerts)中(尽管中间授权不存在,可能是原因吗?)。您的问题似乎与证书问题有关,而不是与代理配置有关。 无论如何,在我的项目中,我使用以下配置:
@Bean
@Autowired
public RestTemplate restTemplate(ClientHttpRequestFactory factory)
{
RestTemplate result = new RestTemplate(factory);
return result;
}
@Bean
public ClientHttpRequestFactory requestFactory() throws Exception
{
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient());
return factory;
}
@Bean
public HttpClient httpClient() throws Exception
{
int timeout = new Integer(env.getProperty("web.http.client.timeout"));
CloseableHttpClient httpClient = null;
//I load a JSON where I specify the name and the PWD of keystores I want to use
String keystores = "keyStoreInfo.json";
PoolingHttpClientConnectionManager pcm = null;
if(StringUtils.hasText(keystores))
{
Resource jsonRes = new ClassPathResource(keystores);
if( jsonRes.exists() )
{
List<KeyStoreInfo> ksInfo = objectMapper().readValue(jsonRes.getInputStream(), new TypeReference<List<KeyStoreInfo>>()
{
});
SSLContext sslCtx = SSLContext.getInstance("TLS");
List<KeyManager> keymanagers = new ArrayList<KeyManager>();
for (KeyStoreInfo ksi : ksInfo)
{
String keystoreName = ksi.getNomeKeyStore();
String keyStorePwd = ksi.getPasswordKeyStore();
if( StringUtils.hasText(keystoreName) )
{
Resource keystoreRes = new ClassPathResource(keystoreName);
KeyMaterial km = new KeyMaterial(keystoreRes.getInputStream(), keyStorePwd.toCharArray());
KeyStore clientStore = km.getKeyStore();
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(clientStore, keyStorePwd != null ? keyStorePwd.toCharArray() : null);
keymanagers.addAll(Arrays.asList(kmfactory.getKeyManagers()));
}
}
if( !keymanagers.isEmpty() )
{
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslCtx.init(keymanagers.toArray(new KeyManager[keymanagers.size()]), new TrustManager[]{tm}, null);
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslCtx);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionFactory).register("http", new PlainConnectionSocketFactory()).build();
pcm = new PoolingHttpClientConnectionManager(registry);
}
else
{
if( logger.isInfoEnabled() )
{
logger.info("Nessun keystore presente nel JSON di configurazione {}. Creo un PoolingHttpClientConnectionManager di default",keystores);
}
pcm = new PoolingHttpClientConnectionManager();
}
}
}
else
{
if( logger.isInfoEnabled() )
{
logger.info("Nessun keystore da caricare. Creo un PoolingHttpClientConnectionManager di default");
}
pcm = new PoolingHttpClientConnectionManager();
}
HttpClientBuilder hcb = HttpClientBuilder.create();
pcm.closeIdleConnections(timeout, TimeUnit.MILLISECONDS);
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).setConnectTimeout(timeout).build();
hcb.setDefaultRequestConfig(config);
hcb.setConnectionManager(pcm).setConnectionManagerShared(true);
boolean proxyEnable = new Boolean(env.getProperty("web.http.client.proxyEnable"));
if (proxyEnable)
{
int proxyPort = new Integer(env.getProperty("web.http.client.portProxy"));
String proxyHost = env.getProperty("web.http.client.hostProxy");
BasicCredentialsProvider credentialProvider = new BasicCredentialsProvider();
AuthScope scope = new AuthScope(proxyHost, proxyPort);
String usernameProxy = env.getProperty("web.http.client.usernameProxy");
String passwordProxy = env.getProperty("web.http.client.passwordProxy");
if (StringUtils.hasText(usernameProxy) && StringUtils.hasText(passwordProxy))
{
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(usernameProxy, passwordProxy);
credentialProvider.setCredentials(scope, credentials);
}
ProxyRoutePlanner proxyRoutPlanner = new ProxyRoutePlanner(new HttpHost(proxyHost, proxyPort), env.getProperty("web.http.client.urlNotProxy"));
hcb.setDefaultCredentialsProvider(credentialProvider).setRoutePlanner(proxyRoutPlanner);
}
WsKeepAliveStrategy cas = new WsKeepAliveStrategy();
cas.setTimeout(new Long(timeout));
hcb.setKeepAliveStrategy(cas);
httpClient = hcb.build();
return httpClient;
}
而ProxyRoutePlanner
是:
public class WsKeepAliveStrategy implements ConnectionKeepAliveStrategy
{
private Long timeout;
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context)
{
return timeout;
}
public void setTimeout(Long timeout)
{
this.timeout = timeout;
}
}
public class ProxyRoutePlanner extends DefaultProxyRoutePlanner
{
private List<String> urlsNotProxy = null;
private boolean useAlwaysSuper = false;
public ProxyRoutePlanner(HttpHost proxy, String urlNotProxy)
{
super(proxy);
if (!StringUtils.hasText(urlNotProxy))
this.useAlwaysSuper = true;
else
{
this.urlsNotProxy = Arrays.asList(urlNotProxy.split(","));
}
}
@Override
public HttpRoute determineRoute(HttpHost host, HttpRequest request, HttpContext context) throws HttpException
{
String hostname = host.getHostName();
if (this.useAlwaysSuper || this.urlsNotProxy.contains(hostname) == false)
return super.determineRoute(host, request, context);// Super method
// with proxy
if ("http".equals(host.getSchemeName()))
return new HttpRoute(host);// Direct Route
HttpClientContext clientContext = HttpClientContext.adapt(context);
RequestConfig config = clientContext.getRequestConfig();
InetAddress local = config.getLocalAddress();
return new HttpRoute(host, local, true);
}
}
公共类ProxyRoutePlanner扩展了DefaultProxyRoutePlanner
{
私有列表urlsNotProxy=null;
私有布尔值UseAllwaysSuber=false;
公共ProxyRoutePlanner(HttpHost代理,字符串urlNotProxy)
{
超级(代理);
如果(!StringUtils.hasText(urlNotProxy))
this.useAllwaysSuper=真;
其他的
{
this.urlsNotProxy=Arrays.asList(urlNotProxy.split(“,”);
}
}
@凌驾
公共HttpRoute determiniteRoute(HttpHost主机、HttpRequest请求、HttpContext上下文)引发HttpException
{
字符串hostname=host.getHostName();
if(this.useAllwaysSuper | | this.urlsNotProxy.contains(hostname)==false)
返回super.determineRoute(主机、请求、上下文);//super方法
//有代理人
if(“http.equals(host.getSchemeName()))
返回新的HttpRoute(主机);//直接路由
HttpClientContext=HttpClientContext.adapt(上下文);
RequestConfig=clientContext.getRequestConfig();
InetAddress local=config.getLocalAddress();
返回新的HttpRoute(主机、本地、true);
}
}
我正在使用此配置,没有任何问题
在任何情况下,您都应该检查在rest调用中需要使用什么类型的证书
我希望它有用
Angelo简单修复,跳过证书即可
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, acceptingTrustStrategy).build();
简短的回答是“是的,您需要信任库中的中间权限,而不仅仅是根CA”。好吧,我的问题非常精确,您的答案非常广泛,这就是我能说的。另外,我不知道“您应该检查在rest调用中需要使用什么类型的证书”是什么意思,您可以通过访问我提供的URL来查看证书。证书由VeriSign签名,我可以在我的信任库中找到根CA。无论如何,我尝试禁用主机验证,因为我没有实现浏览器,只是为单个域实现一个简单的rest客户端。我只是发布了我的配置,通过使用此配置,我在使用证书和代理后都没有问题。你可以自由使用它,也可以不使用它。相反,在你的情况下,例外情况非常明显。。这不是代理,而是证书链,所以我建议你检查一下你回答的是问题的标题,不想读我写的其他东西,是吗?不要猜测,只要亲自查看证书,看看它是否有效。另外,正如我刚才所说的,通过所有验证对我的用例来说是完全有效的方法,所以信任库和密钥库设置对我没有用处。
public class ProxyRoutePlanner extends DefaultProxyRoutePlanner
{
private List<String> urlsNotProxy = null;
private boolean useAlwaysSuper = false;
public ProxyRoutePlanner(HttpHost proxy, String urlNotProxy)
{
super(proxy);
if (!StringUtils.hasText(urlNotProxy))
this.useAlwaysSuper = true;
else
{
this.urlsNotProxy = Arrays.asList(urlNotProxy.split(","));
}
}
@Override
public HttpRoute determineRoute(HttpHost host, HttpRequest request, HttpContext context) throws HttpException
{
String hostname = host.getHostName();
if (this.useAlwaysSuper || this.urlsNotProxy.contains(hostname) == false)
return super.determineRoute(host, request, context);// Super method
// with proxy
if ("http".equals(host.getSchemeName()))
return new HttpRoute(host);// Direct Route
HttpClientContext clientContext = HttpClientContext.adapt(context);
RequestConfig config = clientContext.getRequestConfig();
InetAddress local = config.getLocalAddress();
return new HttpRoute(host, local, true);
}
}
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, acceptingTrustStrategy).build();