Spring Boot SSL 客户端
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30770280/
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
Spring Boot SSL Client
提问by skmansfield
I am new to Spring Boot. So far I am enjoying it. I have developed a demo SSL rest web server that correctly handles mutual X.509 certificate authentication. Using an IE browser with self signed client & server certificates, I have tested that the demo rest web server is working correctly -- both the server and browser are successfully exchanging and validating each others certificates.
我是 Spring Boot 的新手。到目前为止,我很享受。我开发了一个演示 SSL rest web 服务器,它可以正确处理相互 X.509 证书身份验证。使用带有自签名客户端和服务器证书的 IE 浏览器,我测试了演示其余 Web 服务器是否正常工作——服务器和浏览器都成功地交换和验证了彼此的证书。
I am having trouble finding an SSL client example that shows how to include the client certificate and issue the https. Anybody have a simple rest client example that shows how to consume my ssl server?
我无法找到显示如何包含客户端证书并发出 https 的 SSL 客户端示例。任何人都有一个简单的休息客户端示例来展示如何使用我的 ssl 服务器?
Best Regards, Steve Mansfield
最好的问候,史蒂夫·曼斯菲尔德
采纳答案by skmansfield
I could not get the above client submitted by Andy to work. I kept getting errors saying that "localhost != clientname". Anyways, I got this to work correctly.
我无法让安迪提交的上述客户工作。我不断收到错误消息,说“localhost != clientname”。无论如何,我让它正常工作。
import java.io.IOException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.GetMethod;
public class SSLClient {
static
{
System.setProperty("javax.net.ssl.trustStore","c:/apachekeys/client1.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "password");
System.setProperty("javax.net.ssl.keyStore", "c:/apachekeys/client1.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
}
public static void main(String[] args) throws HttpException, IOException {
HttpClient client = new HttpClient();
GetMethod method = new GetMethod();
method.setURI(new URI("https://localhost:8443/restserver", false));
client.executeMethod(method);
System.out.println(method.getResponseBodyAsString());
}
}
回答by Andy Wilkinson
Given that you're using Spring, here's an example that shows how to use Spring's RestTemplate
and Apache's HttpClient
configured with a client certificate and to trust a self-signed certificate from the server:
鉴于您使用的是 Spring,下面的示例展示了如何使用 SpringRestTemplate
和 ApacheHttpClient
配置了客户端证书并信任来自服务器的自签名证书:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(new File("keystore.jks")),
"secret".toCharArray());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "password".toCharArray()).build());
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
ResponseEntity<String> response = restTemplate.getForEntity(
"https://localhost:8443", String.class);
回答by jonashackt
The example of user1707141didn′t work for me and skmansfieldseems rather depending on specific files, that aren′t convention with Spring Boot / Maven. Also Andy Wilkinson′s answer uses the constructor SSLConnectionSocketFactory, which was deprecated in Apache httpclient 4.4+ and also seems quite complex.
user1707141的例子对我不起作用,skmansfield似乎更依赖于特定的文件,这与 Spring Boot / Maven 没有约定。此外安迪·威尔金森的答案使用构造SSLConnectionSocketFactory,这是在Apache的HttpClient的4.4+弃用,也似乎相当复杂。
So I created a example project that should show everything 100% comprehensiblehere: https://github.com/jonashackt/spring-boot-rest-clientcertificate
所以我创建了一个示例项目,它应该在这里显示100% 可理解的所有内容:https: //github.com/jonashackt/spring-boot-rest-clientcertificate
Besides the normal usage of the RestTemplate with @Autowired
in your Testclass, be sure to configure your RestTemplate like this:
除了@Autowired
在您的测试类中正常使用 RestTemplate之外,请确保像这样配置您的 RestTemplate:
package de.jonashackt.restexamples;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
@Configuration
public class RestClientCertTestConfiguration {
private String allPassword = "allpassword";
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
SSLContext sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
.build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
return builder
.requestFactory(new HttpComponentsClientHttpRequestFactory(client))
.build();
}
}
回答by Sireesh Yarlagadda
Other way to do this. Inject the values for keyStoreLocation and keyStorePassword
其他方法来做到这一点。注入 keyStoreLocation 和 keyStorePassword 的值
@Configuration
public class SampleSSLClient extends RestTemplate{
/** The key store password. */
private String keyStorePassword;
/** The key store location. */
private String keyStoreLocation;
/** The rest template. */
@Autowired
private RestTemplate restTemplate;
/** The http components client http request factory. */
private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory;
/**
* Instantiates a new custom rest template.
*/
public CustomRestTemplate() {
super();
}
public CustomRestTemplate(RestTemplate restTemplate){
this.restTemplate = getRestTemplate();
}
/**
* Rest template.
*
* @return the rest template
*/
public RestTemplate getRestTemplate() {
if (null == httpComponentsClientHttpRequestFactory) {
httpComponentsClientHttpRequestFactory = loadCert();
restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
}
return restTemplate;
}
/**
* Load cert.
*
* @return the http components client http request factory
*/
private HttpComponentsClientHttpRequestFactory loadCert() {
try {
char[] keypass = keyStorePassword.toCharArray();
SSLContext sslContext = SSLContextBuilder.create()
.loadKeyMaterial(getkeyStore(keyStoreLocation, keypass), keypass)
.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
} catch (Exception ex) {
LOGGER.error(MessageFormat.format("Some Error", ex.getMessage()), ex);
}
return httpComponentsClientHttpRequestFactory;
}
/**
* Key store.
*
* @param storePath the store path
* @param password the password
* @return the key store
*/
private KeyStore getkeyStore(String storePath, char[] password) {
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
File key = ResourceUtils.getFile(storePath);
try (InputStream in = new FileInputStream(key)) {
keyStore.load(in, password);
}
}catch (Exception ex) {
LOGGER.error(MessageFormat.format("Some Error", ex.getMessage()), ex);
}
return keyStore;
}
/**
* Sets the key store password.
*
* @param keyStorePassword the new key store password
*/
public void setKeyStorePassword(String keyStorePassword) {
this.keyStorePassword = keyStorePassword;
}
/**
* Sets the key store location.
*
* @param keyStoreLocation the new key store location
*/
public void setKeyStoreLocation(String keyStoreLocation) {
this.keyStoreLocation = keyStoreLocation;
}
/**
* Sets the rest template.
*
* @param restTemplate the new rest template
*/
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
回答by user1707141
I know its too late, but here is the code that works for me.
我知道为时已晚,但这是对我有用的代码。
@SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String args[]) {
makeWebServiceCall();
}
public static void makeWebServiceCall() {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext;
ResponseEntity<String> response = null;
try {
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);
StringBuffer plainCreds = new StringBuffer();
plainCreds.append("username");
plainCreds.append(":");
plainCreds.append("password");
byte[] plainCredsBytes = plainCreds.toString().getBytes();
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
String userBase64Credentials = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + userBase64Credentials);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity<>(headers);
String url = "https:restUrl";
response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
if(response.getStatusCodeValue() == 200) {
log.info("Success! Further processing based on the need");
} else {
log.info("****************Status code received: " + response.getStatusCodeValue() + ".************************");
}
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
log.error("Exception occured. Here are the exception details: ", e);
} catch(HttpClientErrorException e) {
if(e.getRawStatusCode() == 403) {
log.info("****************Status code received: " + e.getRawStatusCode() + ". You do not have access to the requested resource.************************");
} else if(e.getRawStatusCode() == 404) {
log.info("****************Status code received: " + e.getRawStatusCode() + ". Resource does not exist(or) the service is not up.************************");
} else if(e.getRawStatusCode() == 400) {
log.info("****************Status code received: " + e.getRawStatusCode() + ". Bad Request.************************");
} else {
log.info("****************Status code received: " + e.getRawStatusCode() + ".************************");
}
log.info("****************Response body: " + e.getResponseBodyAsString() + "************************");
}
}
}
Here is the maven filed
这是 maven 归档
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-consuming-rest</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-databind</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
回答by Pushparaj Dhole
This worked for me :
这对我有用:
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
javax.net.ssl.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);