一、解決方案
1、httpClient請求https版藍鯨接口
(1)、原理
https與http最大的區別在於SSL加密傳輸協議的使用。在自己寫的JAVA HttpClient程序,想手動驗證證書,可以在客戶端繞過驗證服務器證書的步驟,即則需要實現空的X509TrustManager接口。
類中的驗證方法返回void或者null,是為了繞過驗證。正常的方法體如果檢驗出證書無法被信任,需要手動拋出異常:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building
failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
並在chtch中處理異常,如果想要繞過驗證,也就是說不要拋出異常就可以了,可以理解為信任了任何證書。
(2)、代碼展示:HttpsClientUtil.java

import org.apache.http.client.HttpClient; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.CookieSpecs; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.*; import org.apache.http.entity.StringEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; /** * @author xiehaiqing * @date 2019/03/26 */ public class HttpsClientUtil { /** * 在調用SSL之前需要重寫驗證方法,取消檢測SSL * 創建ConnectionManager,添加Connection配置信息 * @return HttpClient 支持https */ public static HttpClient sslClient(){ try { // 在調用SSL之前需要重寫驗證方法,取消檢測SSL X509TrustManager trustManager = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS); ctx.init(null, new TrustManager[]{trustManager}, null); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE); //創建registry RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT) .setExpectContinueEnabled(Boolean.TRUE).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)) .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build(); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", socketFactory).build(); // 創建ConnectionManager,添加Connection配置信息 PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).build(); return closeableHttpClient; }catch (KeyManagementException ex){ throw new RuntimeException(ex); }catch (NoSuchAlgorithmException e){ throw new RuntimeException(e); } } /** * post請求 * @param url * @param jsonStr * @return */ public static String doPost(String url,String jsonStr){ HttpClient httpClient = null; HttpPost httpPost = null; String result = null; try{ httpClient = sslClient(); httpPost = new HttpPost(url); httpPost.addHeader("Content-type","applicattion/json"); StringEntity se = new StringEntity(jsonStr); se.setContentType("text/json"); se.setContentEncoding(new BasicHeader("Content-type","application/json")); httpPost.setEntity(se); HttpResponse response = httpClient.execute(httpPost); if (response !=null){ HttpEntity entity = response.getEntity(); if (entity !=null){ result = EntityUtils.toString(entity,"utf-8"); } } }catch (Exception e){ e.printStackTrace(); } return result; } }
2、模擬https版本登錄
(1)、原理
icube模擬登陸,即是通過服務的登錄鏈接,對用戶輸入的賬號密碼進行真實的驗證,本功能使用了Jsoup解析的方式實現。
具體邏輯為,先使用get請求鏈接的方式,生成登錄所需的bklogin_csrftoken這一屬性字段,然后在通過post攜帶用戶輸入的賬號密碼和該csrftoken字段進行登錄請求,如果用戶輸入的賬號密碼正確,則在cookie中會有一個不為空的bk_token字段,即為登錄成功,否則登錄失敗。對於https請求,需要在請求之前繞過證書驗證,這里采用創建不驗證證書鏈的信任管理器來實現。
登錄鏈接示例:https://xx.com/login/?c_url=
(2)代碼展示

1 import com.zork.opbd.datasource.Config; 2 3 import com.zork.opbd.log.SystemLogHelper; 4 5 import org.jsoup.Connection; 6 7 import org.jsoup.Connection.*; 8 9 import org.jsoup.Jsoup; 10 11 import org.jsoup.nodes.Document; 12 13 import org.jsoup.nodes.Element; 14 15 import org.jsoup.select.Elements; 16 17 18 19 import javax.net.ssl.*; 20 21 import java.security.KeyManagementException; 22 23 import java.security.NoSuchAlgorithmException; 24 25 import java.security.SecureRandom; 26 27 import java.security.cert.CertificateException; 28 29 import java.security.cert.X509Certificate; 30 31 import java.util.*; 32 33 34 35 public class BKLoginUtils { 36 37 public static String LOGIN_URL= Config.getInstance().BK_LOGIN_URL; //https://xx.com/login/?c_url= 38 39 public final static String USER_AGENT="User-Agent"; 40 41 public final static String USER_AGENT_VALUE="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"; 42 43 public final static String LOGINFORM = "#login-form"; 44 45 public final static String NAME = "name"; 46 47 public final static String VALUE = "value"; 48 49 public final static String USERNAME = "username"; 50 51 public final static String PASSWORD = "password"; 52 53 public final static String ID = "id"; 54 55 public final static String USER = "user"; 56 57 public final static String REFERER = "Referer"; 58 59 public final static String BKTOKEN = "bk_token"; 60 61 62 63 64 65 public static void main(String[] args) throws Exception { 66 67 boolean admin = siMulateLogin("admin", "zork.8888"); 68 69 System.out.println(admin); 70 71 } 72 73 74 75 /** 76 77 * 模擬登陸功能 78 79 * @param userName 80 81 * @param pwd 82 83 * @return result 84 85 */ 86 87 public static boolean siMulateLogin(String userName,String pwd){ 88 89 boolean result = false; 90 91 try{ 92 93 checkQuietly(); 94 95 Connection con = Jsoup.connect(LOGIN_URL).timeout(30000).userAgent(USER_AGENT_VALUE); 96 97 Response rs = con.execute(); 98 99 Document doc = Jsoup.parse(rs.body()); 100 101 List<Element> elements = doc.select(LOGINFORM); 102 103 Elements allElements = elements.get(0).getAllElements(); 104 105 Iterator<Element> iterator = allElements.iterator(); 106 107 Map<String,String> datas = new HashMap<>(); 108 109 while (iterator.hasNext()){ 110 111 //賦值 112 113 Element element = iterator.next(); 114 115 if (element.attr(NAME).equals(USERNAME) && element.attr(ID).equals(USER)){ 116 117 element.attr(VALUE,userName); 118 119 } 120 121 if (element.attr(NAME).equals(PASSWORD) && element.attr(ID).equals(PASSWORD)){ 122 123 element.attr(VALUE,pwd); 124 125 } 126 127 //排除空值表單屬性 128 129 if (element.attr(NAME).length()>0){ 130 131 datas.put(element.attr(NAME),element.attr(VALUE)); 132 133 } 134 135 } 136 137 Connection conn = Jsoup.connect(LOGIN_URL); 138 139 conn.header(USER_AGENT,USER_AGENT_VALUE); 140 141 conn.header(REFERER,LOGIN_URL);//注意,這一行必須要加,否則會驗證失敗 142 143 Response login = conn.ignoreContentType(true).followRedirects(true).method(Method.POST).data(datas).cookies(rs.cookies()).execute(); 144 145 Map<String,String> cookies = login.cookies(); 146 147 Iterator<String> keyIter = cookies.keySet().iterator(); 148 149 while (keyIter.hasNext()){ 150 151 String key = keyIter.next(); 152 153 if (BKTOKEN.equals(key)){ 154 155 if (!StringUtil.isNull(cookies.get(key))){ 156 157 SystemLogHelper.info("獲取bk_token成功,bk_token:"+cookies.get(key),true); 158 159 result = true; 160 161 }else { 162 163 SystemLogHelper.info("獲取bk_token失敗,登陸失敗,請檢查用戶名或密碼",true); 164 165 } 166 167 } 168 169 } 170 171 }catch (Exception e){ 172 173 e.printStackTrace(); 174 175 } 176 177 return result; 178 179 } 180 181 182 183 184 185 /** 186 187 * 信任管理器 188 189 * 繞過證書驗證 190 191 */ 192 193 public static void checkQuietly(){ 194 195 try{ 196 197 //創建不驗證證書鏈的信任管理器 198 199 TrustManager[] trustAllCerts = { 200 201 new X509TrustManager() { 202 203 @Override 204 205 public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 206 207 208 209 } 210 211 @Override 212 213 public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 214 215 216 217 } 218 219 @Override 220 221 public X509Certificate[] getAcceptedIssuers() { 222 223 return null; 224 225 } 226 227 } 228 229 }; 230 231 //安裝所有的信任管理器 232 233 SSLContext ssl = SSLContext.getInstance("SSL"); 234 235 ssl.init(null,trustAllCerts,new SecureRandom()); 236 237 HttpsURLConnection.setDefaultSSLSocketFactory(ssl.getSocketFactory()); 238 239 //不驗證主機名 240 241 HostnameVerifier hv = new HostnameVerifier() { 242 243 @Override 244 245 public boolean verify(String s, SSLSession sslSession) { 246 247 return true; 248 249 } 250 251 }; 252 253 HttpsURLConnection.setDefaultHostnameVerifier(hv); 254 255 } catch (NoSuchAlgorithmException | KeyManagementException e) { 256 257 e.printStackTrace(); 258 259 } 260 261 262 263 } 264 265 }