一、解决方案
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 }