利用HttpClient登录校内

先抄录一段简介:

HttpClient简介

HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

网上有大量关于HttpClient的信息,这里就不做介绍了.

回到本文重点,如何利用HttpClient登录校内网?

由于我们要利用HttpClient的特性模仿Browser的登录流程,那自然第一步就是要得到Browser登录校内的具体流程了.

这个流程要怎么得到呢?这就要感谢强大的wireshark分析功能了,利用它可以很轻松的抓取登录时的网络数据包.如何使用wireshark,不是本文重点,网上有大量教程,这里简单说下:Capture->Option->Capture Filter:填入host  youripaddress(这是最简单的,会抓取所有的数据包)然后start就可以了.抓取完了之后,选中某一条记录右键->Follow Tcp Stream,就可以看到这次网络数据包的具体信息了.

下图是我抓到的校内登录过程:

 Login只是一个POST数据的过程,POST的数据包含email,password,originURL,domain这四个参数,那我们只要在利用HttpClient POST数据时,依照这个样子把参数设置进去就行了:

HttpPost httpPost = new HttpPost(loginUri);

            List<NameValuePair> nvp = new ArrayList<NameValuePair>();

            nvp.add(new BasicNameValuePair("email", username));

            nvp.add(new BasicNameValuePair("password", password));

            nvp.add(new BasicNameValuePair("originUrl", originUrl));

            nvp.add(new BasicNameValuePair("domain", domain));

            httpPost.setEntity(new UrlEncodedFormEntity(nvp, HTTP.UTF_8));

然后用httpClient.execute执行这次Post:

                    HttpResponse response = httpClient.execute(httpPost);

这样就完成了一次完整的Login过程,之后可以根据response实据情况再做处理:

在这里它返回了302 Found,表示要再次打开另外一个页面,也就是上图Header 中Location对应的值(Uri).

之后我们可以再利用HttpGet获取这个Uri中的内容,里面应该就是你登录后,看到的内容,只是我们得到的是Html源码文件.

至此我们已经完成了利用HttpClient登录校内的过程,接下来你是不是会想,既然已经登录了,那是不是可以继续做一些事情呢?比如说更新一个状态.

既然想到了这里,还是老办法,利用wireshark抓取Browser更新状态的数据包.

下图是我抓到的一个数据包,更新状态内容为:testabcdefg

这里面共带了4个参数:c,raw,publisher_form_ticket,requestToken

其中c=raw,publisher_form_ticket=requestToken,这两个值为什么会相等,这个我就不得而知了.

这其中的ticket是什么参数呢,从哪个地方可以得到呢?

你对你的Browser点右键,查看网页源代码,把抓到的这个ticket在上面搜索下就可以找到了,既然在网页源码里面可以找到,那我们自然是先要抓取这个网页源码得到ticket才后进行下一步操作.

需要抓取的网页源码就是在Login时看到的Location后面的uri,把这个uri内容抓下来,然后再找到ticket就好了.

        HttpGet httpGet = new HttpGet(uri);

                    try {

                            HttpResponse response = httpClient.execute(httpGet);

                            Log.e(tag, "" + response.getStatusLine());

                            HttpEntity httpEntity = response.getEntity();

                            if (null != httpEntity) {

                                    String entity = EntityUtils.toString(httpEntity);

                                    ticket = getTicket(entity);

                                    Log.e(tag, "ticket=" + ticket);

                                    // Log.e(tag, entity);

                                    httpEntity.consumeContent();

                            }

其中getTicket实现为,这个方法不保证长期有效,只能说目前有效,说不定什么时候校内又更新的网页.

public static String getTicket(String str) {

            str = str.split("publisher_form_ticket\" value=\"")[1];

            return str.split("\"")[0];

    }

得到ticket之后,就可以模拟POST的过程了;

HttpPost httpPost = new HttpPost(postStatusUrl);

            List<NameValuePair> nvp = new ArrayList<NameValuePair>();

            nvp.add(new BasicNameValuePair("c", status));

            nvp.add(new BasicNameValuePair("raw", status));

            String requestToken = ticket;

            nvp.add(new BasicNameValuePair("publisher_form_ticket", ticket));

            nvp.add(new BasicNameValuePair("requestToken", requestToken));

            try {

                    httpPost.setEntity(new UrlEncodedFormEntity(nvp, HTTP.UTF_8));

                    HttpResponse httpResponse = httpClient.execute(httpPost);

可以将它的结果都打印出来看看:

Log.e(tag, "post status finished:" + httpResponse.getStatusLine());

                    HttpEntity httpEntity = httpResponse.getEntity();

                    if (null != httpEntity) {

                            Log.e(tag, EntityUtils.toString(httpEntity));

                    }

如果能看到类似于下面这样的信息就表示成功了:

{"allMsg":"test1234","updateStatusId":1.397876723e9,"dtime":"Sat Sep 11 15:14:57 CST 2010","code":0,"msg":"test1234"}

至此我们已经实现了更新状态的功能,我想其它的功能也类似于这样就可以实现了,这时就不做深究了.

我已经将这些测试 源代码放到github上了:

http://github.com/PercyPeng/sns/tree/

需要的自己clone,直接导入到eclipse就可以了.

main函数入口在SNS.java.