Java 使用restTemplate时需要忽略证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36672803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Need to ignore certificate when using restTemplate
提问by Daniel Newtown
I am trying to send a request to following address. The certificate is not valid and I would like to ignore it. I wrote following code based on my research on 1, 2but I am not able to complete it. I am using Java 1.7,
我正在尝试向以下地址发送请求。证书无效,我想忽略它。我根据对1、2 的研究编写了以下代码,但无法完成。我使用的是 Java 1.7,
https://api.stubhubsandbox.com/search/catalog/events/v3
Code
代码
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers(){
return null;
}
public void checkClientTrusted( X509Certificate[] certs, String authType ){}
public void checkServerTrusted( X509Certificate[] certs, String authType ){}
public void checkClientTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
}
};
public static void main(String[] args) {
TrustStrategy acceptingTrustStrategy =
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
String url = "https://api.stubhubsandbox.com/search/catalog/events/v3";
RestTemplate rest = new RestTemplate();
Map<String, String> mvm = new HashMap<String, String>();
mvm.put("Authorization", "Bearer TOKEEEEEEEN");
Object object = rest.postForObject(url, null, Object.class, mvm);
System.err.println("done");
}
回答by chrisl08
Not sure if things have changed after jdk6, but last time I was trying to do this we needed to import the SSL certificate to the keystore of the JAVA_HOME used to run the programs utilizing the trusted ssl.
不确定在 jdk6 之后情况是否发生了变化,但上次我尝试这样做时,我们需要将 SSL 证书导入到 JAVA_HOME 的密钥库中,该密钥库用于使用受信任的 ssl 运行程序。
First, you will need to export the certificate to a file. In windows, you can use any browser to save the SSL certificate to your personal certificates store and then run mmc, add certificates snapin (File/Add Remove Snapin) and save the certificate to disk.
首先,您需要将证书导出到文件中。在 Windows 中,您可以使用任何浏览器将 SSL 证书保存到您的个人证书存储区,然后运行 mmc,添加证书管理单元(File/Add Remove Snapin)并将证书保存到磁盘。
Then you need to import the certificate to trusted domain cacerts using the keytool. But you need to import it to the keystore that your java_home uses when running your programs above.
然后您需要使用keytool将证书导入受信任的域 cacerts 。但是您需要将它导入到您的 java_home 在运行上面的程序时使用的密钥库。
The command below will add certificate file "mycertificate.cer" to keystore in file "cacerts.jks". The alias is "webservice" :
下面的命令会将证书文件“mycertificate.cer”添加到文件“cacerts.jks”中的密钥库。别名是“webservice”:
"%JAVA_HOME%\bin\keytool" -import -trustcacerts -alias webservice -file mycertificate.cer -keystore cacerts.jks
Usually, the Keystore password is "changeit", no quotes. Change it for production use
通常,密钥库密码是“changeit”,没有引号。将其更改为生产用途
回答by Costi Ciudatu
As you may have noticed, Spring's RestTemplate
delegates all the HTTP(S) related stuff to the underlying implementation of ClientHttpRequestFactory
. Since you're using the HttpClient
-based implementation, here are a couple of useful SO links on how to achieve this for the internal HttpClient
:
您可能已经注意到,SpringRestTemplate
将所有与 HTTP(S) 相关的内容委托给ClientHttpRequestFactory
. 由于您使用的是HttpClient
-based 实现,这里有几个有用的 SO 链接,说明如何为内部实现这一点HttpClient
:
- Ignoring SSL certificate in Apache HttpClient 4.3
- How to ignore SSL certificate errors in Apache HttpClient 4.0
Apparently, since version 4.4, this can be done as:
显然,从 4.4 版开始,这可以通过以下方式完成:
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
回答by mika
To bypass SSL checks in several spring projects I always re-use a SSLUtils class I wrote (or found) some time ago in conjunction with spring's RestTemplate. Using the class provided below you just need to call the static SSLUtil.turnOffSslChecking()
method before you send your request.
为了在几个 spring 项目中绕过 SSL 检查,我总是重新使用我前段时间编写(或找到)的 SSLUtils 类,并结合 spring 的 RestTemplate。使用下面提供的类,您只需要SSLUtil.turnOffSslChecking()
在发送请求之前调用静态方法。
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public final class SSLUtil{
static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
if (hostname.equals("localhost")) {
return true;
}
return false;
}
});
}
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers(){
return null;
}
public void checkClientTrusted( X509Certificate[] certs, String authType ){}
public void checkServerTrusted( X509Certificate[] certs, String authType ){}
}
};
public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext.getInstance("SSL").init( null, null, null );
}
private SSLUtil(){
throw new UnsupportedOperationException( "Do not instantiate libraries.");
}
}
Give it a try. Hope this works and turns out as an easy solution for you.
试一试。希望这行得通,并且对您来说是一个简单的解决方案。
回答by DanieleDM
You can use this code:
您可以使用此代码:
@Bean
public RestTemplate restTemplate()
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
in java 7 replace lambda expression with:
在 Java 7 中,将 lambda 表达式替换为:
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
@Override public boolean isTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
return true;
}
};
回答by Novice
Add the SSLContextand X509TrustManagerand the HostnameVerifierinstances to the http ClientBuilders. They can be for instance (given my example)
将SSLContext和X509TrustManager以及HostnameVerifier实例添加到 http ClientBuilders。例如,它们可以是(以我的示例为例)
- HttpClientBuilder with HttpComponentsClientHttpRequestFactory
- OkHttpClient.Builder with OkHttp3ClientHttpRequestFactory
- 带有 HttpComponentsClientHttpRequestFactory 的 HttpClientBuilder
- OkHttpClient.Builder 和 OkHttp3ClientHttpRequestFactory
Here's the sample code for Apache HttpClient & OkHttpClient. Its for demo purpose but you can use it
这是 Apache HttpClient 和 OkHttpClient 的示例代码。它用于演示目的,但您可以使用它
Apache HttpClient
Apache HttpClient
RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.HttpClient));
and OkHttpClient
和 OkHttpClient
RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.OkHttpClient));
The SSLClientFactory is custom class here
SSLClientFactory 是这里的自定义类
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import okhttp3.OkHttpClient;
public abstract class SSLClientFactory {
private static boolean allowUntrusted = false;
private static final long LOGIN_TIMEOUT_SEC = 10;
private static HttpClientBuilder closeableClientBuilder = null;
private static OkHttpClient.Builder okHttpClientBuilder = null;
public enum HttpClientType{
HttpClient,
OkHttpClient
}
public static synchronized ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientType httpClientType){
ClientHttpRequestFactory requestFactory = null;
SSLContext sslContext = SSLClientFactory.getSSlContext();
if(null == sslContext){
return requestFactory;
}
switch (httpClientType) {
case HttpClient:
closeableClientBuilder = HttpClientBuilder.create();
//Add the SSLContext and trustmanager
closeableClientBuilder.setSSLContext(getSSlContext());
//add the hostname verifier
closeableClientBuilder.setSSLHostnameVerifier(gethostnameVerifier());
requestFactory = new HttpComponentsClientHttpRequestFactory(closeableClientBuilder.build());
break;
case OkHttpClient:
okHttpClientBuilder = new OkHttpClient().newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);
//Add the SSLContext and trustmanager
okHttpClientBuilder.sslSocketFactory(getSSlContext().getSocketFactory(), getTrustManager());
//add the hostname verifier
okHttpClientBuilder.hostnameVerifier( gethostnameVerifier());
requestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClientBuilder.build());
break;
default:
break;
}
return requestFactory;
}
private static SSLContext getSSlContext(){
final TrustManager[] trustAllCerts = new TrustManager[]{getTrustManager()};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
private static X509TrustManager getTrustManager(){
final X509TrustManager trustManager = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
};
return trustManager;
}
private static HostnameVerifier gethostnameVerifier(){
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
return hostnameVerifier;
}
}
回答by Brijesh Patel
If you are using Apache httpClient 4.5 following:
如果您使用的是 Apache httpClient 4.5,请执行以下操作:
public static void main(String... args) {
try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) {
HttpGet httpget = new HttpGet("https://example.com");
System.out.println("Executing request " + httpget.getRequestLine());
httpclient.execute(httpget);
System.out.println("----------------------------------------");
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
throw new RuntimeException(e);
}
}
private static CloseableHttpClient createAcceptSelfSignedCertificateClient()
throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
// use the TrustSelfSignedStrategy to allow Self Signed Certificates
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
// we can optionally disable hostname verification.
// if you don't want to further weaken the security, you don't have to include this.
HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
// create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
// and allow all hosts verifier.
SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);
// finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
return HttpClients
.custom()
.setSSLSocketFactory(connectionFactory)
.build();
}
回答by UDIT JOSHI
@Bean
public RestTemplate getRestTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
This code bypasses the certificate validation and you can connect with an insecure way by accepting all hosts and certificates. This code works for me
此代码绕过证书验证,您可以通过接受所有主机和证书以不安全的方式进行连接。这段代码对我有用
回答by Ganesh Bhattachan
SSLUtils solution posted by @Sebastián Ezquerro is spot on. I tested this both with RestTemplate and FeignClient - works like a champ. Many thanks to all contributors. In case, you are wondering Feign client solution, here it is:
@Sebastián Ezquerro 发布的 SSLUtils 解决方案就在现场。我用 RestTemplate 和 FeignClient 对此进行了测试 - 像冠军一样工作。非常感谢所有贡献者。如果您想知道 Feign 客户端解决方案,这里是:
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
BasicAuthRequestInterceptor auth = new BasicAuthRequestInterceptor(username, password);
RequestTemplate template = new RequestTemplate();
template.header(HttpHeaders.ACCEPT, "application/json");
template.header(HttpHeaders.CONTENT_TYPE, "application/json");
auth.apply(template);
// disable SSL self signed certificate check
try {
SSLUtil.turnOffSslChecking();
} catch (NoSuchAlgorithmException e) {
log.error("Error disabling SSL check", e);
} catch (KeyManagementException e) {
log.error("Error disabling SSL check", e);
}
return auth;
}