原来的老项目调用一个Http的服务,最近http的服务调整成了https,因此需要调整一下,网上大部分都是4.5以上版本,3.1版本处理方法比较少,因此记录一下
一、实现两个类
1.MyX509TrustManager
- import java.security.cert.CertificateException;
- import java.security.cert.X509Certificate;
- import javax.net.ssl.X509TrustManager;
-
- public class MyX509TrustManager implements X509TrustManager {
- /* (non-Javadoc)
- * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String)
- */
- public void checkClientTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
-
- }
- /* (non-Javadoc)
- * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String)
- */
- public void checkServerTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
-
- }
- /* (non-Javadoc)
- * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
- */
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
2.MySecureProtocolSocketFactory
项目使用的jdk版本是1.8,jdk版本默认协议需要指定一下,因此SSLContext context = SSLContext.getInstance("TLSv1.2");
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.TrustManager;
- import org.apache.commons.httpclient.ConnectTimeoutException;
- import org.apache.commons.httpclient.HttpClientError;
- import org.apache.commons.httpclient.params.HttpConnectionParams;
- import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
- import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
-
- public class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {
-
- //添加一个属性,主要目的获取ssl跳过验证
- private SSLContext sslContext = null;
- /**
- * Constructor for MySecureProtocolSocketFactory.
- */
- public MySecureProtocolSocketFactory() {
- }
- /**
- * 创建一个获取SSLContext的方法,导入MyX509TrustManager进行初始化
- * @return
- */
- private static SSLContext createEasySSLContext() {
- try {
- SSLContext context = SSLContext.getInstance("TLSv1.2");
- context.init(null, new TrustManager[] { new MyX509TrustManager() },
- null);
- return context;
- } catch (Exception e) {
- throw new HttpClientError(e.toString());
- }
- }
-
- /**
- * 判断获取SSLContext
- * @return
- */
- private SSLContext getSSLContext() {
- if (this.sslContext == null) {
- this.sslContext = createEasySSLContext();
- }
- return this.sslContext;
- }
- //后面的方法基本上带入相关参数
- /*
- * (non-Javadoc)
- *
- * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String,
- * int, java.net.InetAddress, int)
- */
- public Socket createSocket(String host, int port, InetAddress clientHost,int clientPort) throws IOException, UnknownHostException {
- return getSSLContext().getSocketFactory().createSocket(host, port,clientHost, clientPort);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String,
- * int, java.net.InetAddress, int,
- * org.apache.commons.httpclient.params.HttpConnectionParams)
- */
- public Socket createSocket(final String host, final int port,final InetAddress localAddress, final int localPort,
- final HttpConnectionParams params) throws IOException,UnknownHostException, ConnectTimeoutException {
- if (params == null) {
- throw new IllegalArgumentException("Parameters may not be null");
- }
- int timeout = params.getConnectionTimeout();
- if (timeout == 0) {
- return createSocket(host, port, localAddress, localPort);
- } else {
- return ControllerThreadSocketFactory.createSocket(this, host, port,localAddress, localPort, timeout);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
- */
- public Socket createSocket(String host, int port) throws IOException,UnknownHostException {
- return getSSLContext().getSocketFactory().createSocket(host, port);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
- */
- public Socket createSocket(Socket socket, String host, int port,boolean autoClose) throws IOException, UnknownHostException {
- return getSSLContext().getSocketFactory().createSocket(socket, host,port, autoClose);
- }
- }
最后声明MySecureProtocolSocketFactory加入Protocol就可以了。
- //声明
- ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();
- //加入相关的https请求方式
- Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
- //发送请求
- org.apache.commons.httpclient.HttpClient httpclient = new org.apache.commons.httpclient.HttpClient();
- GetMethod httpget = new GetMethod(url);
- System.out.println("======https的服务地址url:" + url);
- try {
- httpclient.executeMethod(httpget);
- return httpget.getResponseBodyAsString();
- } catch (Exception ex) {
- ex.printStackTrace();
- throw new Exception(ex.getMessage());
- } finally {
- httpget.releaseConnection();
- }
-
实现完后自信满满重新打包更新上正式环境,结果报错了。。。
- javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates do not conform to algorithm constraints
-
-
- at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
-
-
- at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
-
-
- at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
-
-
- at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
-
-
- at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
-
-
- at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
-
-
- at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
-
-
- at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
-
-
- at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
-
-
- at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
百度一下这个问题,证书不符合算法约束,基本都是修改配置文件$JAVA_HOME/jre/lib/security/java.security,但是项目是docker部署的,jdk用的是docker里面的,外面服务器里的jdk版本都是11,那每次更新服务都得手动改配置也太麻烦了吧。。。
===================================================================
后面找到一篇文章,修改前面的实现类,把自己实现的类改写成继承新的抽象类:X509ExtendedTrustManager即可,代码如下:
- //public class MyX509TrustManager implements X509TrustManager {
- public class MyX509TrustManager extends X509ExtendedTrustManager {
- //实现方法,所有方法都是空方法
- }
再次更新代码,问题解决!
参考:httpclient 3.1跳过https请求SSL的验证_鼓逗猫柠的博客-CSDN博客
https://www.cnblogs.com/flyingeagle/articles/7508207.html