• java客户端验证https连接(忽略证书验证和证书验证两种方式)


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

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

    验证客户端pom依赖

    </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.apache.httpcomponents</groupId>
                    <artifactId>httpclient</artifactId>
                    <version>4.5.10</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.httpcomponents</groupId>
                    <artifactId>httpcore</artifactId>
                    <version>4.4.12</version>
                </dependency>

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

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

    跳过证书验证方式

    package com.demo.bootdemo;
    
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.HttpClients;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    
    @Component
    public class SkipVerifyRestTemplateBuilder {
    
    	private Logger logger = LoggerFactory.getLogger(SkipVerifyRestTemplateBuilder.class);
    
    	// 初始化ssl resttemplate
    	@Bean("skipVerifyRestTemplate")
    	public RestTemplate skipVerifyRestTemplate() {
    		RestTemplate rest = new RestTemplate();
    
    		SSLConnectionSocketFactory buildSSLSocketFactory = null;
    		try {
    			buildSSLSocketFactory = this.buildSSLSocketFactory();
    		} catch (Exception e) {
    			logger.error("", e);
    		}
    
    		HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
    				HttpClients.custom().setSSLSocketFactory(buildSSLSocketFactory).build());
    
    		factory.setConnectionRequestTimeout(1000);
    		factory.setConnectTimeout(1000);
    		
    		rest.setRequestFactory(factory);
    		return rest;
    	}
    
    	private SSLConnectionSocketFactory buildSSLSocketFactory() throws Exception {
    		SSLContext sslContext = SSLContext.getInstance("SSL");
    		// 设置信任证书(绕过TrustStore验证)
    		sslContext.init(null, new TrustManager[] { new AuthX509TrustManager() }, null);
    		HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
    
    		SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
    				new String[] { "TLSv1" }, null, new HostnameVerifier() {
    					// hostname,默认返回true,不验证hostname
    					@Override
    					public boolean verify(String urlHostName, SSLSession session) {
    						return true;
    					}
    				});
    		return sslConnectionSocketFactory;
    	}
    
    	private class AuthX509TrustManager implements TrustManager, X509TrustManager {
    		public X509Certificate[] getAcceptedIssuers() {
    			return null;
    		}
    
    		public void checkServerTrusted(X509Certificate[] certs, String authType)
    				throws java.security.cert.CertificateException {
    			return;
    		}
    
    		public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
    			return;
    		}
    	}
    }
    

    第二种跳过证书验证方式

    package com.demo.bootdemo;
    
    import java.io.IOException;
    import java.security.KeyStore;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContexts;
    import org.springframework.context.annotation.Bean;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    
    @Component
    public class SecondSkipVerifyRestTemplateBuilder {
    
        @Bean("secondSkipRestTemplate")
        public RestTemplate verifyCaRestTemplate() {
            RestTemplate rest = new RestTemplate();
            SSLConnectionSocketFactory ssLSocketFactory = null;
            try {
                ssLSocketFactory = sslFactory("PKCS12", "abc123");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
                    HttpClients.custom().setSSLSocketFactory(ssLSocketFactory).build());
            // 设置传递数据超时时长
            httpRequestFactory.setReadTimeout(1000);
    
            rest.setRequestFactory(httpRequestFactory);
    
            // 如果返回的数据非json则可能需要添加对应httpmessageconverter
            // Jaxb2RootElementHttpMessageConverter converter = new
            // Jaxb2RootElementHttpMessageConverter();
            //
            // List<MediaType> mediaTypeList = new ArrayList<>();
            // mediaTypeList.addAll(converter.getSupportedMediaTypes());
            // mediaTypeList.add(MediaType.TEXT_HTML);
            // converter.setSupportedMediaTypes(mediaTypeList);
            //
            // List<HttpMessageConverter<?>> list = new ArrayList<>();
            // list.add(converter);
            // rest.setMessageConverters(list);
    
            return rest;
    
        }
    
        public SSLConnectionSocketFactory sslFactory(String keyStoreType, String keyPassword) {
            SSLConnectionSocketFactory sslConnectionSocketFactory = null;
            try {
                SSLContext sslcontext = SSLContexts.custom()
                        // //忽略掉对服务器端证书的校验
                        .loadTrustMaterial(new TrustStrategy() {
                            @Override
                            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                                return true;
                            }
                        }).build();
                sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
                        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sslConnectionSocketFactory;
        }
    
    }

    根据证书验证

    package com.demo.bootdemo;
    
    import java.io.IOException;
    import java.security.KeyStore;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContexts;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.core.io.Resource;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    
    @Component
    public class VerifyCaRestTemplateBuilder {
    
        private Logger logger = LoggerFactory.getLogger(VerifyCaRestTemplateBuilder.class);
    
        @Value("classpath:cert.p12")
        private Resource certFile;
    
        @Bean("verifyCaRestTemplate")
        public RestTemplate verifyCaRestTemplate() {
            RestTemplate rest = new RestTemplate();
    
            SSLConnectionSocketFactory ssLSocketFactory = null;
            try {
                ssLSocketFactory = sslFactory("PKCS12", "abc123");
            } catch (Exception e) {
                logger.error("", e);
            }
    
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
                    HttpClients.custom().setSSLSocketFactory(ssLSocketFactory).build());
            // 设置传递数据超时时长
            httpRequestFactory.setReadTimeout(1000);
    
            rest.setRequestFactory(httpRequestFactory);
    
            // 如果返回的数据非json则可能需要添加对应httpmessageconverter
            // Jaxb2RootElementHttpMessageConverter converter = new
            // Jaxb2RootElementHttpMessageConverter();
            //
            // List<MediaType> mediaTypeList = new ArrayList<>();
            // mediaTypeList.addAll(converter.getSupportedMediaTypes());
            // mediaTypeList.add(MediaType.TEXT_HTML);
            // converter.setSupportedMediaTypes(mediaTypeList);
            //
            // List<HttpMessageConverter<?>> list = new ArrayList<>();
            // list.add(converter);
            // rest.setMessageConverters(list);
    
            return rest;
    
        }
    
        public SSLConnectionSocketFactory sslFactory(String keyStoreType, String keyPassword) {
            SSLConnectionSocketFactory sslConnectionSocketFactory = null;
            try {
                KeyStore keyStore = null;
                try {
                    keyStore = KeyStore.getInstance(keyStoreType);
                    keyStore.load(certFile.getInputStream(), keyPassword.toCharArray());
                } catch (IOException e) {
                    logger.error("", e);
                }
    
                HostnameVerifier hv = new HostnameVerifier() {
                    @Override
                    public boolean verify(String urlHostName, SSLSession session) {
                        // 如果需要验证https域名,可以在该处做判断,如果访问的hostname与判断不一致,则会出现如下异常
                        // if("localhost".equals(urlHostName)) {
                        // return true;
                        // }else {
                        // return false;
                        // }
                        // 此处不校验hostname,接收所有hostname,只是用于测试。
                        return true;
                    }
                };
    
                SSLContext sslcontext = SSLContexts.custom()
                        .loadTrustMaterial(certFile.getFile(), keyPassword.toCharArray(), new TrustSelfSignedStrategy())
                        .loadKeyMaterial(keyStore, keyPassword.toCharArray()).build();
                sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, hv);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sslConnectionSocketFactory;
        }
    
    }

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

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

    测试controller

    package com.demo.bootdemo;
    
    import javax.annotation.Resource;
    
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.client.RestTemplate;
    
    @Controller
    public class HttpsSendController {
    
        @Resource(name = "skipVerifyRestTemplate")
        private RestTemplate skipVerifyRestTemplate;
    
        @Resource(name = "verifyCaRestTemplate")
        private RestTemplate verifyCaRestTemplate;
    
        @Resource(name = "secondSkipRestTemplate")
        private RestTemplate secondSkipRestTemplate;
    
        @RequestMapping("/skip")
        @ResponseBody
        public String skipVerifyCert() {
            ResponseEntity<String> forEntity = skipVerifyRestTemplate.getForEntity("https://127.0.0.1:8443/test",
                    String.class, new Object[] {});
            return forEntity.getBody();
        }
    
        @RequestMapping("/secondskip")
        @ResponseBody
        public String secondSkipVerifyCert() {
            ResponseEntity<String> forEntity = skipVerifyRestTemplate.getForEntity("https://127.0.0.1:8443/test",
                    String.class, new Object[] {});
            return forEntity.getBody();
        }
    
        @RequestMapping("/verify")
        @ResponseBody
        public String verifyCert() {
            ResponseEntity<String> forEntity = verifyCaRestTemplate.getForEntity("https://127.0.0.1:8443/test",
                    String.class, new Object[] {});
            return forEntity.getBody();
        }
    
    }

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

  • 相关阅读:
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    软件工程实践总结
  • 原文地址:https://www.cnblogs.com/qq931399960/p/11904157.html
Copyright © 2020-2023  润新知