首先根据如下操作生成证书,配置springboot https,生成一个简单的https web服务

https://www.cnblogs.com/qq931399960/p/11889349.html

验证客户端pom依赖

  1. </dependency>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.httpcomponents</groupId>
  8. <artifactId>httpclient</artifactId>
  9. <version>4.5.10</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.apache.httpcomponents</groupId>
  13. <artifactId>httpcore</artifactId>
  14. <version>4.4.12</version>
  15. </dependency>

httpclient和httpcore版本要对应,否则可能会出现异常

验证方式包括跳过证书验证,也即是添加信任,就像浏览器访问自签名https服务时,页面会给出提示“您的链接不是私密连接”,点击了高级,继续前往即是对该服务添加了信任,可以继续访问该网站服务,另外一种方式就是通过服务器证书来验证,下面就直接上代码

跳过证书验证方式

  1. package com.demo.bootdemo;
  2.  
  3. import java.security.cert.CertificateException;
  4. import java.security.cert.X509Certificate;
  5.  
  6. import javax.net.ssl.HostnameVerifier;
  7. import javax.net.ssl.HttpsURLConnection;
  8. import javax.net.ssl.SSLContext;
  9. import javax.net.ssl.SSLSession;
  10. import javax.net.ssl.TrustManager;
  11. import javax.net.ssl.X509TrustManager;
  12.  
  13. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  14. import org.apache.http.impl.client.HttpClients;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import org.springframework.context.annotation.Bean;
  18. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  19. import org.springframework.stereotype.Component;
  20. import org.springframework.web.client.RestTemplate;
  21.  
  22. @Component
  23. public class SkipVerifyRestTemplateBuilder {
  24.  
  25. private Logger logger = LoggerFactory.getLogger(SkipVerifyRestTemplateBuilder.class);
  26.  
  27. // 初始化ssl resttemplate
  28. @Bean("skipVerifyRestTemplate")
  29. public RestTemplate skipVerifyRestTemplate() {
  30. RestTemplate rest = new RestTemplate();
  31.  
  32. SSLConnectionSocketFactory buildSSLSocketFactory = null;
  33. try {
  34. buildSSLSocketFactory = this.buildSSLSocketFactory();
  35. } catch (Exception e) {
  36. logger.error("", e);
  37. }
  38.  
  39. HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
  40. HttpClients.custom().setSSLSocketFactory(buildSSLSocketFactory).build());
  41.  
  42. factory.setConnectionRequestTimeout(1000);
  43. factory.setConnectTimeout(1000);
  44. rest.setRequestFactory(factory);
  45. return rest;
  46. }
  47.  
  48. private SSLConnectionSocketFactory buildSSLSocketFactory() throws Exception {
  49. SSLContext sslContext = SSLContext.getInstance("SSL");
  50. // 设置信任证书(绕过TrustStore验证)
  51. sslContext.init(null, new TrustManager[] { new AuthX509TrustManager() }, null);
  52. HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
  53.  
  54. SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
  55. new String[] { "TLSv1" }, null, new HostnameVerifier() {
  56. // hostname,默认返回true,不验证hostname
  57. @Override
  58. public boolean verify(String urlHostName, SSLSession session) {
  59. return true;
  60. }
  61. });
  62. return sslConnectionSocketFactory;
  63. }
  64.  
  65. private class AuthX509TrustManager implements TrustManager, X509TrustManager {
  66. public X509Certificate[] getAcceptedIssuers() {
  67. return null;
  68. }
  69.  
  70. public void checkServerTrusted(X509Certificate[] certs, String authType)
  71. throws java.security.cert.CertificateException {
  72. return;
  73. }
  74.  
  75. public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
  76. return;
  77. }
  78. }
  79. }

第二种跳过证书验证方式

  1. package com.demo.bootdemo;
  2. import java.io.IOException;
  3. import java.security.KeyStore;
  4. import java.security.cert.CertificateException;
  5. import java.security.cert.X509Certificate;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import javax.net.ssl.HostnameVerifier;
  9. import javax.net.ssl.HttpsURLConnection;
  10. import javax.net.ssl.SSLContext;
  11. import javax.net.ssl.SSLSession;
  12. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  13. import org.apache.http.conn.ssl.TrustStrategy;
  14. import org.apache.http.impl.client.HttpClients;
  15. import org.apache.http.ssl.SSLContexts;
  16. import org.springframework.context.annotation.Bean;
  17. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  18. import org.springframework.stereotype.Component;
  19. import org.springframework.web.client.RestTemplate;
  20. @Component
  21. public class SecondSkipVerifyRestTemplateBuilder {
  22. @Bean("secondSkipRestTemplate")
  23. public RestTemplate verifyCaRestTemplate() {
  24. RestTemplate rest = new RestTemplate();
  25. SSLConnectionSocketFactory ssLSocketFactory = null;
  26. try {
  27. ssLSocketFactory = sslFactory("PKCS12", "abc123");
  28. } catch (Exception e) {
  29. // TODO Auto-generated catch block
  30. e.printStackTrace();
  31. }
  32. HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
  33. HttpClients.custom().setSSLSocketFactory(ssLSocketFactory).build());
  34. // 设置传递数据超时时长
  35. httpRequestFactory.setReadTimeout(1000);
  36. rest.setRequestFactory(httpRequestFactory);
  37. // 如果返回的数据非json则可能需要添加对应httpmessageconverter
  38. // Jaxb2RootElementHttpMessageConverter converter = new
  39. // Jaxb2RootElementHttpMessageConverter();
  40. //
  41. // List<MediaType> mediaTypeList = new ArrayList<>();
  42. // mediaTypeList.addAll(converter.getSupportedMediaTypes());
  43. // mediaTypeList.add(MediaType.TEXT_HTML);
  44. // converter.setSupportedMediaTypes(mediaTypeList);
  45. //
  46. // List<HttpMessageConverter<?>> list = new ArrayList<>();
  47. // list.add(converter);
  48. // rest.setMessageConverters(list);
  49.  
  50. return rest;
  51. }
  52. public SSLConnectionSocketFactory sslFactory(String keyStoreType, String keyPassword) {
  53. SSLConnectionSocketFactory sslConnectionSocketFactory = null;
  54. try {
  55. SSLContext sslcontext = SSLContexts.custom()
  56. // //忽略掉对服务器端证书的校验
  57. .loadTrustMaterial(new TrustStrategy() {
  58. @Override
  59. public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  60. return true;
  61. }
  62. }).build();
  63. sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
  64. SSLConnectionSocketFactory.getDefaultHostnameVerifier());
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. }
  68. return sslConnectionSocketFactory;
  69. }
  70. }

根据证书验证

  1. package com.demo.bootdemo;
  2. import java.io.IOException;
  3. import java.security.KeyStore;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import javax.net.ssl.HostnameVerifier;
  7. import javax.net.ssl.SSLContext;
  8. import javax.net.ssl.SSLSession;
  9. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  10. import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
  11. import org.apache.http.impl.client.HttpClients;
  12. import org.apache.http.ssl.SSLContexts;
  13. import org.slf4j.Logger;
  14. import org.slf4j.LoggerFactory;
  15. import org.springframework.beans.factory.annotation.Value;
  16. import org.springframework.context.annotation.Bean;
  17. import org.springframework.core.io.Resource;
  18. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  19. import org.springframework.stereotype.Component;
  20. import org.springframework.web.client.RestTemplate;
  21. @Component
  22. public class VerifyCaRestTemplateBuilder {
  23. private Logger logger = LoggerFactory.getLogger(VerifyCaRestTemplateBuilder.class);
  24. @Value("classpath:cert.p12")
  25. private Resource certFile;
  26. @Bean("verifyCaRestTemplate")
  27. public RestTemplate verifyCaRestTemplate() {
  28. RestTemplate rest = new RestTemplate();
  29. SSLConnectionSocketFactory ssLSocketFactory = null;
  30. try {
  31. ssLSocketFactory = sslFactory("PKCS12", "abc123");
  32. } catch (Exception e) {
  33. logger.error("", e);
  34. }
  35. HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
  36. HttpClients.custom().setSSLSocketFactory(ssLSocketFactory).build());
  37. // 设置传递数据超时时长
  38. httpRequestFactory.setReadTimeout(1000);
  39. rest.setRequestFactory(httpRequestFactory);
  40. // 如果返回的数据非json则可能需要添加对应httpmessageconverter
  41. // Jaxb2RootElementHttpMessageConverter converter = new
  42. // Jaxb2RootElementHttpMessageConverter();
  43. //
  44. // List<MediaType> mediaTypeList = new ArrayList<>();
  45. // mediaTypeList.addAll(converter.getSupportedMediaTypes());
  46. // mediaTypeList.add(MediaType.TEXT_HTML);
  47. // converter.setSupportedMediaTypes(mediaTypeList);
  48. //
  49. // List<HttpMessageConverter<?>> list = new ArrayList<>();
  50. // list.add(converter);
  51. // rest.setMessageConverters(list);
  52.  
  53. return rest;
  54. }
  55. public SSLConnectionSocketFactory sslFactory(String keyStoreType, String keyPassword) {
  56. SSLConnectionSocketFactory sslConnectionSocketFactory = null;
  57. try {
  58. KeyStore keyStore = null;
  59. try {
  60. keyStore = KeyStore.getInstance(keyStoreType);
  61. keyStore.load(certFile.getInputStream(), keyPassword.toCharArray());
  62. } catch (IOException e) {
  63. logger.error("", e);
  64. }
  65. HostnameVerifier hv = new HostnameVerifier() {
  66. @Override
  67. public boolean verify(String urlHostName, SSLSession session) {
  68. // 如果需要验证https域名,可以在该处做判断,如果访问的hostname与判断不一致,则会出现如下异常
  69. // if("localhost".equals(urlHostName)) {
  70. // return true;
  71. // }else {
  72. // return false;
  73. // }
  74. // 此处不校验hostname,接收所有hostname,只是用于测试。
  75. return true;
  76. }
  77. };
  78. SSLContext sslcontext = SSLContexts.custom()
  79. .loadTrustMaterial(certFile.getFile(), keyPassword.toCharArray(), new TrustSelfSignedStrategy())
  80. .loadKeyMaterial(keyStore, keyPassword.toCharArray()).build();
  81. sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, hv);
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. }
  85. return sslConnectionSocketFactory;
  86. }
  87. }

 注:在上述HostnameVerifier 中,可以验证hostname有效性,如果无效,返回fase,则会出现类似以下异常

javax.net.ssl.SSLPeerUnverifiedException: Certificate for <localhost> doesn\’t match any of the subject alternative names: []

测试controller

  1. package com.demo.bootdemo;
  2. import javax.annotation.Resource;
  3. import org.springframework.http.ResponseEntity;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.ResponseBody;
  7. import org.springframework.web.client.RestTemplate;
  8. @Controller
  9. public class HttpsSendController {
  10. @Resource(name = "skipVerifyRestTemplate")
  11. private RestTemplate skipVerifyRestTemplate;
  12. @Resource(name = "verifyCaRestTemplate")
  13. private RestTemplate verifyCaRestTemplate;
  14. @Resource(name = "secondSkipRestTemplate")
  15. private RestTemplate secondSkipRestTemplate;
  16. @RequestMapping("/skip")
  17. @ResponseBody
  18. public String skipVerifyCert() {
  19. ResponseEntity<String> forEntity = skipVerifyRestTemplate.getForEntity("https://127.0.0.1:8443/test",
  20. String.class, new Object[] {});
  21. return forEntity.getBody();
  22. }
  23. @RequestMapping("/secondskip")
  24. @ResponseBody
  25. public String secondSkipVerifyCert() {
  26. ResponseEntity<String> forEntity = skipVerifyRestTemplate.getForEntity("https://127.0.0.1:8443/test",
  27. String.class, new Object[] {});
  28. return forEntity.getBody();
  29. }
  30. @RequestMapping("/verify")
  31. @ResponseBody
  32. public String verifyCert() {
  33. ResponseEntity<String> forEntity = verifyCaRestTemplate.getForEntity("https://127.0.0.1:8443/test",
  34. String.class, new Object[] {});
  35. return forEntity.getBody();
  36. }
  37. }

可分别访问当前客户端的skip、secondskip、verify验证结果

 

版权声明:本文为qq931399960原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/qq931399960/p/11904157.html