• 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验证结果

  • 相关阅读:
    断点续传的原理
    中国无线音乐搜索综合测评结果
    从头开始学jsp
    SQLServer和Oracle常用函数对比
    Asp.net程序重启自己
    What Can I do if "The type initializer for 'Emgu.CV.CvInvoke' threw an exception"?
    C++Builder2010多线程调用WebService的问题
    Desmon and Penny
    C#显示摄像头预览
    甲骨文78亿美金并购全球第二芯片商AMD
  • 原文地址:https://www.cnblogs.com/qq931399960/p/11904157.html
Copyright © 2020-2023  润新知