首页 文章

Spring Boot SSL客户端

提问于
浏览
7

我是Spring Boot的新手 . 到目前为止,我很享受 . 我开发了一个演示SSL休息Web服务器,可以正确处理相互X.509证书身份验证 . 使用带有自签名客户端和服务器证书的IE浏览器,我测试了演示休息Web服务器是否正常工作 - 服务器和浏览器都成功地交换和验证彼此的证书 .

我在查找SSL客户端示例时遇到问题,该示例显示了如何包含客户端证书并发布https . 有人有一个简单的休息客户端示例,显示如何使用我的ssl服务器?

最诚挚的问候,Steve Mansfield

6 回答

  • 10

    鉴于你是一个例子,它展示了如何使用Spring的 RestTemplate 和Apache的 HttpClient 配置了客户端证书,并信任来自服务器的自签名证书:

    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);
    
  • 0

    我无法让安迪提交的上述客户工作 . 我一直收到错误,说“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());
    
         }
    
     }
    
  • 0

    user1707141的例子对我不起作用,skmansfield似乎更依赖于特定的文件,这不是Spring Boot / Maven的惯例 . 另外Andy Wilkinson的答案使用构造函数SSLConnectionSocketFactory,它在Apache httpclient 4.4中已弃用,而且看起来也很复杂 .

    所以我创建了一个示例项目,应该在这里显示100%可理解的内容:https://github.com/jonashackt/spring-boot-rest-clientcertificate

    除了在Testclass中正常使用RestTemplate和 @Autowired 之外,一定要像这样配置你的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();
        }
    }
    
  • -3

    我知道为时已晚,但这里的代码对我有用 .

    @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() + "************************");
    		}
    	}
     }
    

    这是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.jackson.core</groupId>
            <artifactId>jackson-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>
    
  • 7

    其他方式来做到这一点 . 注入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;
        }
    
  • 5

    这对我有用:

    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);
    

相关问题