真是艹蛋的一次经历,jdk6上面去访问别人的https,还好有百度搞定了问题.现在写下随笔,记录下;
首先要自己重写SSLSocketFactory这个类,
下面是自己重写的这个类:TLSSocketConnectionFactory
1package cn.cbsw.tools; 2 3import java.io.ByteArrayInputStream; 4import java.io.ByteArrayOutputStream; 5import java.io.DataOutputStream; 6import java.io.FileInputStream; 7import java.io.IOException; 8import java.io.InputStream; 9import java.io.OutputStream; 10import java.net.InetAddress; 11import java.net.InetSocketAddress; 12import java.net.Socket; 13import java.net.UnknownHostException; 14import java.security.KeyStore; 15import java.security.Principal; 16import java.security.SecureRandom; 17import java.security.Security; 18import java.security.cert.CertificateExpiredException; 19import java.security.cert.CertificateFactory; 20import java.util.Hashtable; 21import java.util.LinkedList; 22import java.util.List; 23 24import javax.net.ssl.HandshakeCompletedListener; 25import javax.net.ssl.SSLPeerUnverifiedException; 26import javax.net.ssl.SSLSession; 27import javax.net.ssl.SSLSessionContext; 28import javax.net.ssl.SSLSocket; 29import javax.net.ssl.SSLSocketFactory; 30import javax.security.cert.X509Certificate; 31 32import org.bouncycastle.crypto.tls.Certificate; 33import org.bouncycastle.crypto.tls.CertificateRequest; 34import org.bouncycastle.crypto.tls.DefaultTlsClient; 35import org.bouncycastle.crypto.tls.ExtensionType; 36import org.bouncycastle.crypto.tls.TlsAuthentication; 37import org.bouncycastle.crypto.tls.TlsClientProtocol; 38import org.bouncycastle.crypto.tls.TlsCredentials; 39import org.bouncycastle.jce.provider.BouncyCastleProvider; 40 41/** 42 * 建立一个自己的ssl类 43 */ 44public class TLSSocketConnectionFactory extends SSLSocketFactory{ 45 46 static { 47 if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { 48 Security.addProvider(new BouncyCastleProvider()); 49 } 50 } 51 52 @Override 53 public Socket createSocket(Socket socket, final String host, int port, 54 boolean arg3) throws IOException { 55 if (socket == null) { 56 socket = new Socket(); 57 } 58 if (!socket.isConnected()) { 59 socket.connect(new InetSocketAddress(host, port)); 60 } 61 62 final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), new SecureRandom()); 63 64 return _createSSLSocket(host, tlsClientProtocol); 65 } 66 67 @Override public String[] getDefaultCipherSuites() { return null; } 68 @Override public String[] getSupportedCipherSuites() { return null; } 69 @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return null; } 70 @Override public Socket createSocket(InetAddress host, int port) throws IOException { return null; } 71 @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return null; } 72 @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return null; } 73 74 private SSLSocket _createSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) { 75 return new SSLSocket() { 76 private java.security.cert.Certificate[] peertCerts; 77 78 @Override public InputStream getInputStream() throws IOException { return tlsClientProtocol.getInputStream(); } 79 @Override public OutputStream getOutputStream() throws IOException { return tlsClientProtocol.getOutputStream(); } 80 @Override public synchronized void close() throws IOException { tlsClientProtocol.close(); } 81 @Override public void addHandshakeCompletedListener( HandshakeCompletedListener arg0) { } 82 @Override public boolean getEnableSessionCreation() { return false; } 83 @Override public String[] getEnabledCipherSuites() { return null; } 84 @Override public String[] getEnabledProtocols() { return null; } 85 @Override public boolean getNeedClientAuth() { return false; } 86 87 @Override 88 public SSLSession getSession() { 89 return new SSLSession() { 90 91 /*原本这些方法都是直接throw UnsupportedOperationException 导致看不到真实异常*/ 92 @Override 93 public int getApplicationBufferSize() { 94 return 0; 95 } 96 @Override public String getCipherSuite() { return null; } 97 @Override public long getCreationTime() { return 0; } 98 @Override public byte[] getId() { return null; } 99 @Override public long getLastAccessedTime() { return 0; } 100 @Override public java.security.cert.Certificate[] getLocalCertificates() { return null; } 101 @Override public Principal getLocalPrincipal() { return null; } 102 @Override public int getPacketBufferSize() { return 0; } 103 @Override public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { return null; } 104 @Override public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { return peertCerts; } 105 @Override public String getPeerHost() { return null; } 106 @Override public int getPeerPort() { return 0; } 107 @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { return null; } 108 @Override public String getProtocol() { return null; } 109 @Override public SSLSessionContext getSessionContext() { return null; } 110 @Override public Object getValue(String arg0) { return null; } 111 @Override public String[] getValueNames() { return null; } 112 @Override public void invalidate() { return; } 113 @Override public boolean isValid() { return true; } 114 @Override public void putValue(String arg0, Object arg1) { return; } 115 @Override 116 public void removeValue(String arg0) { 117 return; 118 } 119 }; 120 } 121 122 @Override public String[] getSupportedProtocols() { return null; } 123 @Override public boolean getUseClientMode() { return false; } 124 @Override public boolean getWantClientAuth() { return false; } 125 @Override public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) { } 126 @Override public void setEnableSessionCreation(boolean arg0) { } 127 @Override public void setEnabledCipherSuites(String[] arg0) { } 128 @Override public void setEnabledProtocols(String[] arg0) { } 129 @Override public void setNeedClientAuth(boolean arg0) { } 130 @Override public void setUseClientMode(boolean arg0) { } 131 @Override public void setWantClientAuth(boolean arg0) { } 132 @Override public String[] getSupportedCipherSuites() { return null; } 133 134 @Override 135 public void startHandshake() throws IOException { 136 tlsClientProtocol.connect(new DefaultTlsClient() { 137 138 @SuppressWarnings("unchecked") 139 @Override 140 public Hashtable<Integer, byte[]> getClientExtensions() throws IOException { 141 Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions(); 142 if (clientExtensions == null) { 143 clientExtensions = new Hashtable<Integer, byte[]>(); 144 } 145 146 //Add host_name 147 byte[] host_name = host.getBytes(); 148 149 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 150 final DataOutputStream dos = new DataOutputStream(baos); 151 dos.writeShort(host_name.length + 3); 152 dos.writeByte(0); 153 dos.writeShort(host_name.length); 154 dos.write(host_name); 155 dos.close(); 156 clientExtensions.put(ExtensionType.server_name, baos.toByteArray()); 157 return clientExtensions; 158 } 159 160 @Override 161 public TlsAuthentication getAuthentication() throws IOException { 162 return new TlsAuthentication() { 163 164 @Override 165 public void notifyServerCertificate(Certificate serverCertificate) throws IOException { 166 try { 167 KeyStore ks = _loadKeyStore(); 168 169 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 170 List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>(); 171 boolean trustedCertificate = false; 172 for ( org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) { 173 java.security.cert.Certificate cert = cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())); 174 certs.add(cert); 175 176 String alias = ks.getCertificateAlias(cert); 177 if(alias != null) { 178 if (cert instanceof java.security.cert.X509Certificate) { 179 try { 180 ( (java.security.cert.X509Certificate) cert).checkValidity(); 181 trustedCertificate = true; 182 } catch(CertificateExpiredException cee) { 183 // Accept all the certs! 184 } 185 } 186 } else { 187 // Accept all the certs! 188 } 189 190 } 191 if (!trustedCertificate) { 192 // Accept all the certs! 193 } 194 peertCerts = certs.toArray(new java.security.cert.Certificate[0]); 195 } catch (Exception ex) { 196 ex.printStackTrace(); 197 throw new IOException(ex); 198 } 199 } 200 201 @Override 202 public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { 203 return null; 204 } 205 206 private KeyStore _loadKeyStore() throws Exception { 207 FileInputStream trustStoreFis = null; 208 try { 209 KeyStore localKeyStore = null; 210 211 String trustStoreType = System.getProperty("javax.net.ssl.trustStoreType")!=null?System.getProperty("javax.net.ssl.trustStoreType"):KeyStore.getDefaultType(); 212 String trustStoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider")!=null?System.getProperty("javax.net.ssl.trustStoreProvider"):""; 213 214 if (trustStoreType.length() != 0) { 215 if (trustStoreProvider.length() == 0) { 216 localKeyStore = KeyStore.getInstance(trustStoreType); 217 } else { 218 localKeyStore = KeyStore.getInstance(trustStoreType, trustStoreProvider); 219 } 220 221 char[] keyStorePass = null; 222 String str5 = System.getProperty("javax.net.ssl.trustStorePassword")!=null?System.getProperty("javax.net.ssl.trustStorePassword"):""; 223 224 if (str5.length() != 0) { 225 keyStorePass = str5.toCharArray(); 226 } 227 228 localKeyStore.load(trustStoreFis, keyStorePass); 229 230 if (keyStorePass != null) { 231 for (int i = 0; i < keyStorePass.length; i++) { 232 keyStorePass[i] = 0; 233 } 234 } 235 } 236 return localKeyStore; 237 } finally { 238 if (trustStoreFis != null) { 239 trustStoreFis.close(); 240 } 241 } 242 } 243 }; 244 } 245 246 }); 247 } // startHandshake 248 }; 249 } 250}
依赖jar包:
bcpkix-jdk15on-1.60.jar
bcprov-jdk15on-1.60.jar
然后再写一个httpsConnectionUtils工具类:
1package cn.cbsw.tools; 2 3import java.io.BufferedReader; 4import java.io.DataOutputStream; 5import java.io.InputStreamReader; 6import java.net.URL; 7import java.net.URLEncoder; 8import java.security.cert.CertificateException; 9import java.security.cert.X509Certificate; 10import java.util.ArrayList; 11import java.util.Iterator; 12import java.util.List; 13import java.util.Map; 14 15import javax.net.ssl.HostnameVerifier; 16import javax.net.ssl.HttpsURLConnection; 17import javax.net.ssl.SSLContext; 18import javax.net.ssl.SSLSession; 19import javax.net.ssl.TrustManager; 20import javax.net.ssl.X509TrustManager; 21 22import org.apache.commons.lang.StringUtils; 23 24/** 25 * 本类是解决https访问问题 26 * @author sun 27 * 28 */ 29public class HttpsConnectUtils { 30 31 /** 32 * 获取url内容 33 */ 34 public static String getQuery(String desUrl,String method,Map<String,String> params) throws Throwable{ 35 if(!"POST".equalsIgnoreCase(method)){ 36 method="GET";//如果不是POST就认为是GET,至于PUT很少用到,暂时用不到 37 } 38 String paramStr=""; 39 if(params!=null && !params.isEmpty()){ 40 List<String> list=new ArrayList<String>();//存放参数 41 Iterator<String> it=params.keySet().iterator(); 42 while(it.hasNext()){ 43 String key=it.next(); 44 list.add(key+"="+URLEncoder.encode(params.get(key), "utf-8")); 45 } 46 paramStr=StringUtils.join(list,"&"); 47 } 48 //如果是get请求且带有参数 49 if(!"".equals(paramStr) && "GET".equalsIgnoreCase(method)){ 50 desUrl+="?"+paramStr; 51 } 52 URL url = new URL(null,desUrl,new sun.net.www.protocol.https.Handler()); 53 SSLContext sslContext=SSLContext.getInstance("TLS"); 54 TrustManager x509TrustManager=new X509TrustManager() { 55 56 @Override 57 public X509Certificate[] getAcceptedIssuers() { 58 return null; 59 } 60 61 @Override 62 public void checkServerTrusted(X509Certificate[] arg0, String arg1) 63 throws CertificateException { 64 65 } 66 67 @Override 68 public void checkClientTrusted(X509Certificate[] arg0, String arg1) 69 throws CertificateException { 70 71 } 72 }; 73 sslContext.init(null, new TrustManager[]{x509TrustManager}, null); 74 HttpsURLConnection httpsConn=(HttpsURLConnection) url.openConnection(); 75 httpsConn.setSSLSocketFactory(new TLSSocketConnectionFactory()); 76 httpsConn.setRequestProperty("accept", "*/*"); 77 httpsConn.setRequestProperty("connection", "Keep-Alive"); 78 httpsConn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows xp)"); 79 httpsConn.setDoOutput(true); 80 httpsConn.setDoInput(true); 81 httpsConn.setRequestMethod(method!=null?method:"GET");//默认get 82 //忽略证书设置 83 httpsConn.setHostnameVerifier(new HostnameVerifier() { 84 @Override 85 public boolean verify(String arg0, SSLSession arg1) { 86 return true; 87 } 88 }); 89 //下面的方法会自动修改请求方式为POST 90 if(!"".equals(paramStr) && "POST".equalsIgnoreCase(method)){ 91 DataOutputStream out = new DataOutputStream(httpsConn.getOutputStream()); 92 out.writeBytes(paramStr); 93 out.flush(); 94 out.close(); 95 } 96 97 InputStreamReader isr = new InputStreamReader(httpsConn.getInputStream(), "utf-8"); 98 BufferedReader inReader = new BufferedReader(isr); 99 StringBuffer result = new StringBuffer(); 100 String inputLine; 101 while ((inputLine = inReader.readLine()) != null) { 102 result.append(inputLine); 103 } 104 // 关闭输入流 105 inReader.close(); 106 isr.close(); 107 httpsConn.disconnect();//每次请求完毕后关闭链接 108 return result.toString(); 109 } 110}
然后调用的时候直接按httpsConnectionUtils.getQuery(String desUrl,String method,Map<String,String> params)调用即可.
通过百度整整坑了一个星期总算搞定.另外jdk1.8版的工具类也发下httpsConnectionUtils
1package cn.cbsw.tools; 2 3import java.io.BufferedReader; 4import java.io.DataOutputStream; 5import java.io.InputStreamReader; 6import java.net.URL; 7import java.net.URLEncoder; 8import java.security.cert.CertificateException; 9import java.security.cert.X509Certificate; 10import java.util.ArrayList; 11import java.util.Iterator; 12import java.util.List; 13import java.util.Map; 14 15import javax.net.ssl.HostnameVerifier; 16import javax.net.ssl.HttpsURLConnection; 17import javax.net.ssl.SSLContext; 18import javax.net.ssl.SSLSession; 19import javax.net.ssl.TrustManager; 20import javax.net.ssl.X509TrustManager; 21 22import org.apache.commons.lang.StringUtils; 23 24/** 25 * 本类是解决https访问问题 26 * @author sun 27 * 28 */ 29public class HttpsConnectUtils { 30 31 /** 32 * 获取url内容 33 */ 34 public static String getQuery(String desUrl,String method,Map<String,String> params) throws Throwable{ 35 if(!"POST".equalsIgnoreCase(method)){ 36 method="GET";//如果不是POST就认为是GET,至于PUT很少用到,暂时用不到 37 } 38 String paramStr=""; 39 if(params!=null && !params.isEmpty()){ 40 List<String> list=new ArrayList<String>();//存放参数 41 Iterator<String> it=params.keySet().iterator(); 42 while(it.hasNext()){ 43 String key=it.next(); 44 list.add(key+"="+URLEncoder.encode(params.get(key), "utf-8")); 45 } 46 paramStr=StringUtils.join(list,"&"); 47 } 48 //如果是get请求且带有参数 49 if(!"".equals(paramStr) && "GET".equalsIgnoreCase(method)){ 50 desUrl+="?"+paramStr; 51 } 52 URL url = new URL(null,desUrl,new sun.net.www.protocol.https.Handler()); 53 SSLContext sslContext=SSLContext.getInstance("TLSv1.2");//jdk8支持1.2版本 54 TrustManager x509TrustManager=new X509TrustManager() { 55 56 @Override 57 public X509Certificate[] getAcceptedIssuers() { 58 return null; 59 } 60 61 @Override 62 public void checkServerTrusted(X509Certificate[] arg0, String arg1) 63 throws CertificateException { 64 65 } 66 67 @Override 68 public void checkClientTrusted(X509Certificate[] arg0, String arg1) 69 throws CertificateException { 70 71 } 72 }; 73 sslContext.init(null, new TrustManager[]{x509TrustManager}, null); 74 HttpsURLConnection httpsConn=(HttpsURLConnection) url.openConnection(); 75 httpsConn.setSSLSocketFactory(sslContext.getSocketFactory()); 76 httpsConn.setRequestProperty("accept", "*/*"); 77 httpsConn.setRequestProperty("connection", "Keep-Alive"); 78 httpsConn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows xp)"); 79 httpsConn.setDoOutput(true); 80 httpsConn.setDoInput(true); 81 httpsConn.setRequestMethod(method!=null?method:"GET");//默认get 82 //忽略证书设置 83 httpsConn.setHostnameVerifier(new HostnameVerifier() { 84 @Override 85 public boolean verify(String arg0, SSLSession arg1) { 86 return true; 87 } 88 }); 89 //下面的方法会自动修改请求方式为POST 90 if(!"".equals(paramStr) && "POST".equalsIgnoreCase(method)){ 91 DataOutputStream out = new DataOutputStream(httpsConn.getOutputStream()); 92 out.writeBytes(paramStr); 93 out.flush(); 94 out.close(); 95 } 96 97 InputStreamReader isr = new InputStreamReader(httpsConn.getInputStream(), "utf-8"); 98 BufferedReader inReader = new BufferedReader(isr); 99 StringBuffer result = new StringBuffer(); 100 String inputLine; 101 while ((inputLine = inReader.readLine()) != null) { 102 result.append(inputLine); 103 } 104 // 关闭输入流 105 inReader.close(); 106 isr.close(); 107 httpsConn.disconnect();//每次请求完毕后关闭链接 108 return result.toString(); 109 } 110}
希望能帮到后来人!
总的来说升级jdk到1.8肯定是最好方案,不得以才会用上面方法.
也感谢那些善于分享经验的人!