记一次通过程序自动登录需SSO认证的网站
2017-08-02 22:03
302 查看
背景
一个朋友,做车险的,业务员。每天系统会产生大量的险单,而这些数据,他需要手动录入到EXCEL中,留作它用。时间久了,感觉手动处理太过于麻烦,请我帮忙能不能写一个程序,自动把数据按要求写入EXCEL中。思路
之前做过网页爬取、数据提取等案例,感觉问题不大,用到的工具就是firebug、httpclient、jsoup、poi。分析firebug抓取到的HTTP相关数据包,找出业务相关的URL、需要的参数、请求头、以及响应数据格式。然后使用httpclient模拟客户端与服务端进行交互,对响应结果进行解析(如果响应的数据是html,使用jsoup可以很方便的获取想要的数据,如果是json,就更简单了,直接使用第三方的json库,转化成数据封装对象),最后将数据整理、使用第三方库poi按要求将数据写入EXCEL中。
问题
本来想的是直接请求业务URL,处理即可。没想到的是,这个URL访问需要认证登录才可以,直接访问的话,会被拒绝,拿到401响应码。看来,只能分析这个网站的认证登录流程,然后使用httpclient模拟完成认证。动手
当时没有详细去了解下CAS认证协议,仅仅是通过数据包分析去完成认证登录的业务流程。所以下面的代码也是过程式的,没有去重构。package com.ztbx.auth; import java.util.ArrayList; import java.util.List; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import com.ztbx.util.SimpleHttpClient; /** * 完成cas认证 * * @author cjw */ public class CasLogin { protected static final Log log = LogFactory.getLog(CasLogin.class); static final String FIRST_URL = "http://xxx.xxx.xxx.xxx:xxxx/prpcar/main/index"; static final String CAS = "http://xx.xx.xx.xx:xx/casserver/login;jsessionid="; public static void login() throws Exception { //先去请求一下目标地址 HttpResponse firstResp = SimpleHttpClient.requestPost(FIRST_URL, null); log.info("step1状态码:" + firstResp.getStatusLine().getStatusCode()); String authURL = ""; if (firstResp.getStatusLine().getStatusCode() == 302) { //需要认证 Header[] hs = firstResp.getHeaders("Location"); authURL = hs[0].getValue(); } SimpleHttpClient.printResponse(firstResp); //访问认证URL HttpResponse secondResp = SimpleHttpClient.requestPost(authURL, null); log.info("step2状态码:" + secondResp.getStatusLine().getStatusCode()); String respHtml = SimpleHttpClient.printResponse(secondResp); //解析隐藏域的参数 String ltparam = null; String executionparam = null; if (respHtml != null) { String ltkey = "<input type=\"hidden\" name=\"lt\" value=\""; int ltbi = respHtml.indexOf(ltkey); String temp = respHtml.substring(ltbi + ltkey.length()); int ltei = temp.indexOf("\" />"); ltparam = temp.substring(0, ltei); log.info("ltparam:" + ltparam); String executionkey = "<input type=\"hidden\" name=\"execution\" value=\""; int executionbi = temp.indexOf(executionkey); temp = temp.substring(executionbi + executionkey.length()); int executionei = temp.indexOf("\" />"); executionparam = temp.substring(0, executionei); log.info("executionparam:" + executionparam); } //需要获取JSESSIONID String scStr = SimpleHttpClient.getCookies(secondResp); String jsessionid = scStr.substring("JSESSIONID=".length(), scStr.indexOf(";")); String casURL = CAS + jsessionid + authURL.substring(authURL.indexOf("?")); //http://xx.xx.xx.xx:xx/casserver/login;jsessionid=pYn3WqdFTqQvCSZQnK1SQtGyBv0RxWRg84R0RhNQCzzkn6Kx6ymN!811231245?service=http%3A%2F%2Fxx.xx.xx.xx%3Axxxx%2Fprpcar%2Fj_spring_cas_security_check%3BJSESSIONIDPRPCAR69%3DMWWhWqcZ0mgBh5kyKKTLcLT84wrFznWy7pff7yTJ7fTzYDH02nHN%21-1319107732&renew=true //读取配置文件,获取用户登录信息 PropertiesConfiguration config = new PropertiesConfiguration("ztbx.properties"); //模拟登录 List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("lt", ltparam)); params.add(new BasicNameValuePair("execution", executionparam)); params.add(new BasicNameValuePair("_eventId", "submit")); params.add(new BasicNameValuePair("username", config.getString("username"))); params.add(new BasicNameValuePair("password", config.getString("password"))); HttpResponse response = SimpleHttpClient.requestPost(casURL, params); log.info("step3状态码:" + response.getStatusLine().getStatusCode()); SimpleHttpClient.printResponse(response); String ticketCheckURL = ""; if (response.getStatusLine().getStatusCode() == 302) { //重定向 Header[] hs = response.getHeaders("Location"); ticketCheckURL = hs[0].getValue(); } HttpResponse fourResp = SimpleHttpClient.requestPost(ticketCheckURL, null); log.info("step4状态码:" + fourResp.getStatusLine().getStatusCode()); SimpleHttpClient.printResponse(fourResp); String destURL = ""; if (fourResp.getStatusLine().getStatusCode() == 302) { Header[] hs = fourResp.getHeaders("Location"); destURL = hs[0].getValue(); } HttpResponse fiveResp = SimpleHttpClient.requestPost(destURL, null); log.info("step5状态码:" + fiveResp.getStatusLine().getStatusCode()); SimpleHttpClient.printResponse(fiveResp); //验证 String validMacURL = ""; if (fiveResp.getStatusLine().getStatusCode() == 302) { Header[] hs = fiveResp.getHeaders("Location"); validMacURL = hs[0].getValue(); } HttpResponse sixResp = SimpleHttpClient.requestPost(validMacURL, null); log.info("step6状态码:" + sixResp.getStatusLine().getStatusCode()); SimpleHttpClient.printResponse(sixResp); //访问目标首页 String destIndex = ""; if (sixResp.getStatusLine().getStatusCode() == 302) { Header[] hs = sixResp.getHeaders("Location"); destIndex = hs[0].getValue(); } HttpResponse resp = SimpleHttpClient.requestPost(destIndex, null); log.info("最终状态码:" + resp.getStatusLine().getStatusCode()); SimpleHttpClient.printResponse(resp); } }
HTTP客户端工具类:
这个类注意下它的类成员变量,这个客户端是使用了一个长连接,为的就是能像浏览器一样,把这次会话给保持住,避免后续模拟的业务查询被认为是一个新的连接,而重新认证(当然,也可以每次使用的时候重新创建一个连接,然后把cookie传进去,可以达到同样的效果)。
package com.ztbx.util; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.ParseException; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; /** * HTTP客户端 * * @author cjw */ public class SimpleHttpClient { protected static final Log log = LogFactory.getLog(SimpleHttpClient.class); //创建CookieStore实例 static CookieStore cookieStore = null; static HttpClient httpclient = null; static Header[] headers = null; static { cookieStore = new BasicCookieStore(); httpclient = HttpClients.custom() .setDefaultCookieStore(cookieStore) .setDefaultHeaders(defaultHeader()) .build(); } private static List<Header> defaultHeader() { ArrayList<Header> headers = new ArrayList<Header>(); headers.add(new BasicHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0")); headers.add(new BasicHeader(HttpHeaders.ACCEPT, "application/json, text/javascript, */*; q=0.01")); headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")); headers.add(new BasicHeader(HttpHeaders.ACCEPT_CHARSET, "GBK,utf-8;q=0.7,*;q=0.7")); return headers; } public static HttpResponse requestPost(String url, List<NameValuePair> params) throws Exception { HttpPost httppost = new HttpPost(url); httppost.setHeaders(headers); if (params!= null && !params.isEmpty()) { httppost.setEntity(new UrlEncodedFormEntity(params)); } HttpResponse response = httpclient.execute(httppost); return response; } public static String getCookies(HttpResponse response) { Header[] headers = response.getHeaders("Set-Cookie"); StringBuilder sb = new StringBuilder(); for (Header header : headers) { sb.append(header.getValue()).append(";"); } return sb.toString(); } public static void printAllHeader(HttpResponse response) { Header[] headers = response.getAllHeaders(); for (Header header : headers) { log.info(header.getName() + " " + header.getValue()); } } public static String printResponse(HttpResponse httpResponse) throws ParseException, IOException { // 获取响应消息实体 HttpEntity entity = httpResponse.getEntity(); // 响应状态 log.info("status:" + httpResponse.getStatusLine()); log.info("headers:"); HeaderIterator iterator = httpResponse.headerIterator(); while (iterator.hasNext()) { log.info("\t" + iterator.next()); } // 判断响应实体是否为空 String responseString = null; if (entity != null) { responseString = EntityUtils.toString(entity, "UTF-8"); log.info("response length:" + responseString.length()); log.info("response content:" + responseString.replace("\r\n", "")); } return responseString; } }
相关文章推荐
- 关于通过Cookie进行网站自动登录的安全问题
- jsp通过Cookie实现网站自动登录
- 通过VBS编写自动输入账号和密码、自动登录程序的脚本
- 使用程序自动登录网站
- JAVA通过Session和Cookie实现网站自动登录的技术
- 解决通过Cookie进行网站自动登录的安全性问题
- JAVA通过Session和Cookie实现网站自动登录的技术
- JSP 通过Session和Cookie实现网站自动登录
- 通过Basic认证,访问带有账户登录验证的网站资源
- java通过Cookie实现网站自动登录
- 通过VBS编写自动输入账号和密码、自动登录程序的脚本
- python网络爬虫之使用scrapy自动登录网站
- 编写程序自动登录Gmail
- Ubuntu下通过SSH远程登录服务器并运行程序的方法
- iOS UIWebView 通过 cookie 完成自动登录验证
- Cookie-网站登录-下次自动登录
- iOS UIWebView 通过 cookie 完成自动登录验证
- windowsXP系统开机登录界面如何禁止(通过注册表实现自动登录)
- 在ASP.NET登录页面中如何实现文本框焦点自动跳转及通过回车键提交表单
- 写了一个Windows服务,通过C#模拟网站用户登录并爬取BUG列表查询有没有新的BUG,并提醒我