2016年8月31日00:03:40
本人android新手,就读于安阳师范学院,最近在做教务系统登陆的案例,也是在拜读了网上很多做过类似案例的博客,发表一下自己的一点见解。
抓包过程演示
{1} 先找到我们需要在android 端模拟登陆的教务系统网站,我这里先使用一个类似教务系统网站的网站,(是我们学校的一个网络学习中心)来实现模拟登陆,原理都是一样的,并无差别。
打开火狐浏览器的firebug 工具
找到登陆界面,填写我们的账号 和 密码
(注意事项:在firebug界面的 ”保持“ 选项要选中,这样才能看懂到 post请求)
登陆成功后,我们来看第一条,标识有 post 状态 为(302 或者 200)
在这个里面 分别有 头信息 , post 数据,cookies 这三个是比较重要的,
头信息中可以知道
Cookie JSESSIONID=3478af40-368a-4f91-a467-01ec789f1fd2.Test01 (这个主要用于标识我们的身份,就是让服务器知道你是 张三,而不是李四,这个很重要。)
Referer
Referer http://202.196.240.54/portal/relogin (这个就是我们需要在android 端使用到的进行post登陆网址)
下面来看 post 的相关数据项(我把密码涂掉了)
这个是很简单的没有太多参数
eid 对应就是 账号
pw 对应就是 密码
submit 对应是登陆(这只是个参数,没有卵用,而且它需要 url编码 ,可以看见在下面的 源代码中 是这样的:%E7%99%BB++%E5%BD%95 到时候在代码中实现 是这样的 : URLEncoder.encode(“登陆”, “gbk”))
这些数据项我们都要用到,至少针对这个 post 是这样的,但是有些数据项会很多,在android 模拟登陆的时候我还不太清楚是不是有些不用提交。
来看 cookies 说白了就是我们在 头信息中 cookie(3478af40-368a-4f91-a467-01ec789f1fd2.Test01 ) 的值,我就不上图了
【分割线***********************************************************
针对上面的post 中数据项少,我把正常情况的数据项贴出来,并并做出一些解释和我想询问的问题:
这个 是我们学校教务系统登陆后的 post 数据项
在这里我解释一下我怎么没用我们学校的教务系统来写这个.
我们学校使用的教务系统是青果的,我在分析这个 post数据项的时候 ,发现
txt_pewerwedsdfsdff
txt_sdertfgsadscxcadsads
这两个都是空值,这两个我看过网页源码 一个是 密码 一个是 验证码,可是为什么是空值,答案就在 上面的这两个参数
dsdsdsdsdxcxdfgfg
fgfggfdgtyuuyyuuckjg
第一个是密码,第二个是验证码,这个是因为它进行了 md5 加密,将密码 和 验证码 加密了,而且我在看网页源码的时候,找到了 加密过程 和 加密算法,
unction chkpwd(obj) // 加密密码的
{ if(obj.value!='')
{
var s=md5(document.all.txt_asmcdefsddsd.value+md5(obj.value).substring(0,30).toUpperCase()+'10479').substring(0,30).toUpperCase();
document.all.dsdsdsdsdxcxdfgfg.value=s;} else { document.all.dsdsdsdsdxcxdfgfg.value=obj.value;} }
// 加密验证码的
function chkyzm(obj) { if(obj.value!='') { var s=md5(md5(obj.value.toUpperCase()).substring(0,30).toUpperCase()+'10479').substring(0,30).toUpperCase(); document.all.fgfggfdgtyuuyyuuckjg.value=s;} else { document.all.fgfggfdgtyuuyyuuckjg.value=obj.value.toUpperCase();}}//-->
//加密算法,贴出来一部分
unction md5js(pass, code, uin) {
var I = hexchar2bin(md5(pass));
var H = md5(I + uin);
var G = md5(H + code.toUpperCase());
return G
}
var hexcase = 1;
var b64pad = "";
var chrsz = 8;
var mode = 32;
function md5(A) {
return hex_md5(A)
}
function hex_md5(A) {
return binl2hex(core_md5(str2binl(A), A.length * chrsz))
}
function str_md5(A) {
return binl2str(core_md5(str2binl(A), A.length * chrsz))
}
function hex_hmac_md5(A, B) {
return binl2hex(core_hmac_md5(A, B))
}
所以我在android 实现登陆我们学校的教务系统的时候,就出现了问题,因为我在发送参数的 只能发送 post 请求那样写的 参数,所以我自己要将加密过程实现,或者还有其它的方法,但我没想到。
出现这个好像是只要在 青果的教务系统 上, 正方的教务系统 应该是没有加密。
如果那位大神知道怎么弄,需要可以解决一下。
分割线***********************************************】
好了,我们言归正传,对登陆过程的抓包,基本就是这些了。
下面我们将利用到我们得到的东西,在android 端实现这个过程,我们先明确一下过程.
【0】写好我们的登陆界面,并加上网络访问权限
【1】拿到我们需要登陆的网址 http://202.196.240.54/portal/relogin
【2】使用 HttpClient 相关类来 实现登陆过程
【3】设置我们需要参数 (post的数据项)
【4】判断访问是否成功 (==200)
【5】拿到返回的 cookies
【6】拿到响应的网页源码,并且使用 jsoup 解析,这样就拿到我们需要的信息。
【7】将获取的信息,在控件上显示出来。
代码展示 :
【0】登陆界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.aynu.dengluanli.MainActivity" >
<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账号" />
<EditText
android:id="@+id/id_ed"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/pwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码" />
<EditText
android:id="@+id/pwd_ed"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/tijiao"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onclick"
android:text="登陆" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/id_text_infor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="144803085"
android:textSize="30sp" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/name_text_infor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="***"
android:textSize="30sp" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/sj_text_infor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2016年8月30日"
android:textSize="20sp" />
LinearLayout>
LinearLayout>
下面的三个 textview 等会我们会拿到我们的个人信息,然后更新上去。
网络访问权限 : android.permission.INTERNET (因为我们需要访问网络)
【1】登陆网站的过程 (其中有些我写有注解)
// 提交按钮的点击事件
public void onclick(View v) {
new Thread(new Runnable() { // 耗时操作必须使用子线程
@Override
public void run() {
try {
String un = username.getText().toString().trim(); // 获取填写的 用户名
String pwd = password.getText().toString().trim(); // 获取填写的 密码
// 【1】进行post 请求 使用httpclient
client = new DefaultHttpClient();//【1.1】 实例化的httpclient 对象
// 【1.2】进行post请求
HttpPost httpPost = new HttpPost(postURL);
// postURL 就是我们获得网址
// 【1.3】设置要进行 post请求的参数
List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("eid", un));
list.add(new BasicNameValuePair("pw", pwd));
list.add(new BasicNameValuePair("submit", URLEncoder.encode("登陆", "gbk"))); // 上面出现的一个乱码部分,使用了url编码
// 提交表单信息
httpPost.setEntity(new UrlEncodedFormEntity(list, "UTF-8"));
// 响应请求
HttpResponse httpResponse = client.execute(httpPost);
// 判断状态码 如果为 200 则要检查表单 如果为 302 继续
// //有的,其实我通过HttpWatch抓取的返回值就是302,只不过创建HttpClient时用的new
// DefaultHttpClient()
// 这个函数会直接跳转200,如果你用了DefaultHttpClient还是返回302的话,你可以 location
// = response.getFirstHeader("Location").getValue()
// location中有你想要的网址,然后再重新Post新网址就好
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 获取 cookie
cookies = client.getCookieStore().getCookies(); // 拿到的cookies 返回形式是 List
HttpEntity entity = httpResponse.getEntity();
String main_html = EntityUtils.toString(entity); // 这个就是响应的网页源码
IsLoginSuccessful(main_html); // 这个方法是jsoup 解析的方法,可以先不看
} else {
System.out.println(" 请求失败");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
在这里说一下我的一些看法,
(1)你获得到 cookie 后,可以跟 咱们之前在网站上 获取到的 cookie 进行对比,但是 会出现两种情况,一种是 cookie 整好比对上,并且每次都不会变化, 还有一种是 cookie 都会变化(当然这个是 账号 密码 都正确,不是账号密码不正确出现的),但是 这个不影响你的操作, 我还不清楚这个是怎么回事, 但是这个在你 携带 cookie 进行请求的时候,不会出现问题,你只需要将你拿到的 cookie 设置进去就行。
(1)你怎么才能知道你 登陆成功了么,在我们做的判断的地方
if (httpResponse.getStatusLine().getStatusCode() == 200) 这个只是请求是否成功的标志,并不是你登陆 是否成功的标志,你要查看你返回的 网页源码,通过看这个 你就知道你 是否登陆 成功了。
或者你通过 jsoup 看能不能 抓取到 关于登陆成功 出现的信息。 都是可以的。
演示:
登陆没有成功返回的源码(一部分)
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="/library/skin/tool_base.css" type="text/css" rel="stylesheet" media="all" />
<link href="/library/skin/neo-bupt-blue/tool.css" type="text/css" rel="stylesheet" media="all" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>Sakaititle>
<script type="text/javascript" src="/library/js/jquery/1.4.2/jquery-1.4.2.min.js">script>
<script type="text/javascript" language="JavaScript" src="/library/js/headscripts.js">script>
<meta name="viewport" content="width=device-width"/>
head>
<body onload="if ((document.getElementById('pw').passwordfocus != true)) document.getElementById('eid'
).focus() ;parent.updCourier(doubleDeep, ignoreCourier);">
<script type="text/javascript" language="JavaScript">
focus_path = ["eid"];
script>
<table class="login" cellpadding="0" cellspacing="0" border="0">
<tr>
<th colspan="2">登 录th>
tr>
<tr>
<td class="logo">td>
<td class="form">
<form method="post" action="http://202.196.240.54/portal/relogin" enctype="application/x-www-form-urlencoded"
>
<div class="alertMessage">登录信息不正确div>
<table border="0" class="loginform">
<tr>
<td><label for="eid">用户名label>td>
<td><input name="eid" id="eid" value="144803085" type="text" size="15"/>td>
tr>
登陆成功返回的源码(一部分)
<html lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Language" content="zh-CN" />
<script type="text/javascript">
var portal = {
"chat": {
"enabled": false,
"pollInterval": 5000,
"video": {},
"translations": {
"server_unavailable": "It looks like the chat server is unavailable. Check your network
connection.",
"server_error_send" : "Failed to send message. Reason: ",
"server_error_send_error": "Error: "
},
},
"loggedIn": true,
"portalPath": "http://202.196.240.54/portal",
"loggedOutUrl": "http://202.196.240.54/portal",
"siteId": "~144803085",
"siteTitle": "我的工作空间",
"shortDescription": "",
"locale": "zh-CN",
"user": {
"id": "144803085",
"eid": "144803085"
},
(3) 我们获取到的 cookie存放在 List 中,所以写一个方法,将 cookie的值读出来,方便我们在接下来 携带 cookie 请求时使用。
/**
* 解析保存到的 cookies
* @return cookies 值
*/
public String parseCookie(){
// 判断cookies 是不是为空
if (cookies.isEmpty()) {
System.out.println("cookies为空");
}else { // cookies 不为空,就从list中取出cookies 的value 值
for (int i = 0; i < cookies.size(); i++) {
Cookie cookie = cookies.get(i);
System.out.println(cookies.get(i).getName()+"===="+cookies.get(i).getValue());
cookies_value = cookies.get(i).getValue(); //拿到我们的 cookie 类型为 string
}
}
return cookies_value;
}
返回的结果 : 2474bce1-9ce1-4618-97de-dc861c48dcf6.Test01
这样基本上,登陆过程就结束了。
先写到这里,明天继续写。