Android模拟登录教务系统

一、原理

  • 在超级课程表等APP中,大都有使用学号密码登录教务系统读取课程的功能。在这里我将模仿此功能使用J2V8、Jsoup等第三方库实现模拟登录教务系统读取信息。
  • 这里的教务系统以南昌大学教务系统(湖南强智科技教务系统)为例。

现在的大多数网站架构都是后台使用Session来进行用户验证,并向前端返回Cookie,前端的每次请求都带上这个Cookie以作为用户登陆态的保持与身份的认证。
另有部分网站(尤其是APP)使用JWT(JSON Web Tokens)进行登陆态验证,确认登录后前端请求带上返回的Token,也是大同小异。这里主要以前者为例。


我们先来梳理一下登录的流程

1. 前端向后台Servlet发送请求,返回验证码图片。请求头中携带Cookie。
向后台请求验证码图片
2.登录时,请求头中携带相应Cookie,并将账号密码编码后连同验证码一同post到后台
登录
3.若后台验证账号密码与验证码正确,则该Cookie已经作为本用户登录态的凭证,每次请求携带该Cookie即可访问相应权限的Url。

二、具体实现

  • 在Android代码中,我将所有Activity均继承于BaseActivity,BaseActivity中实现沉浸式标题栏的相应代码,将配置文件中的主题修改为@style/Theme.AppCompat.Light.NoActionBar以完成沉浸式标题栏。
/**
 * 封装可复用的代码,作为所有Activity的父类
 */
public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //region 沉浸式状态栏代码
        // 5.0以上系统状态栏透明
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
        //endregion
        setContentView(getViewId());
    }

    /**
     *添加抽象方法,供子类绑定视图
     * @return
     */
    abstract int getViewId();
}
  • 继续进行功能分析,首先,我们要向相应的Servlet发送请求,将验证码显示在App上。
  • 在这里我们使用的是jsoup: Java HTML Parser进行网络链接以及Cookie获取。

我们可以直接在jsoup官网下载对应jar包。为方便起见,我们在Maven Repository中找到jsoup的gradle依赖,并将其添加到build.gradledependencies中。

compile group: 'org.jsoup', name: 'jsoup', version: '1.11.2'

然后我们使用jsoup进行验证码的请求,并将Cookie信息保存下来。
(注:jsoup对网络的请求写在子线程中,通过handle对前端进行操作)

private String url_safecode = "http://jwc101.ncu.edu.cn/jsxsd/verifycode.servlet"; // 验证码
private Map<String, String> cookie;
class PicThread extends Thread{
        @Override
        public void run() {
            Connection.Response response = null;
            try {
                response = Jsoup.connect(url_safecode)
                        .ignoreContentType(true) // 获取图片需设置忽略内容类型
                        .userAgent("Mozilla")
                        .method(Connection.Method.GET).timeout(3000).execute();
                cookie = response.cookies();  //将cookie保存下来
                byte[] bytes = response.bodyAsBytes();
                //验证码保存为Bitmap
                Bitmap bitmap= BitmapFactory.decodeByteArray(bytes,0,bytes.length); 
                Message message=new Message();
                message.what=0x123;
                message.obj=bitmap;
                handler.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

Handle接受到Message后将验证码显示在界面的ImageView上。

handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if(msg.what==0x123){
                    imageView.setImageBitmap((Bitmap)msg.obj);
                }
            }
        };

OK,我们现在将验证码显示了出来并保存了Cookie,接下来就是将账号与密码Post到后台。这里要注意一个问题,我们通过之前的截图可以看到,登录时Post的账号与密码都是重新编码过的。
我们通过右键查看网页源代码可以看到,该编码过程账号和密码分别是调用conwork.js中的encodeInp方法,然后将编码后的密文用%%%进行连接。

编码

  • 这里有两种解决方案,一种解决方案是将加密算法使用Java重写一遍,这种方法比较麻烦,我在这里采用的是第二种方法,直接在Android中使用J2V8框架运行JS代码进行加密。

J2V8框架的添加方式与jsoup大同小异,在maven repository中找到J2V8的gradle依赖,然后添加到build.gradle中。

compile 'com.eclipsesource.j2v8:j2v8:4.5.0@aar'

将conwork.js放到项目目录的assets中,然后使用J2V8调用。

try {
        InputStream is=getAssets().open("conwork.js");   //获取用户名与密码加密的js代码
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
                while ((line = reader.readLine()) != null) {
                        sb.append(line);
                }
                V8 runtime = V8.createV8Runtime();      //使用J2V8运行js代码并将编码结果返回
                final String encodename = runtime.executeStringScript(sb.toString()
                                + "encodeInp('"+userin.getText().toString()+"');\n");
                final String encodepwd=runtime.executeStringScript(sb.toString()+"encodeInp('"+pwdin.getText().toString()+"');\n");
                runtime.release();
        } catch (IOException e) {
                e.printStackTrace();
        } finally {
                try {
                        is.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
} catch (IOException e) {
        e.printStackTrace();
}

然后我们将encodenameencodepwd使用jsoup来post到教务系统登录的url,post时带上之前保存的cookie。

(new Thread(){
        @Override
        public void run() {
                Map<String, String> data = new HashMap<String, String>();   //进行Post的参数
                data.put("encoded", encodename+"%%%"+encodepwd);
                data.put("RANDOMCODE", verin.getText().toString());
                Connection connect = Jsoup.connect(url_Login)
                                        .header("Accept",
                                                "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                                        .userAgent("Mozilla").method(Connection.Method.POST).data(data).timeout(3000);
                for (Map.Entry<String, String> entry : cookie.entrySet()) { //使用获取验证码时生成的cookie
                        connect.cookie(entry.getKey(), entry.getValue());
                }
                Connection.Response response = null;
                try {
                        response = connect.execute();
                        Pattern p=Pattern.compile("<title>(.*)</title>");
                        Matcher m =p .matcher(response.body()) ;
                        if( m. find()) {
                                //通过response的title是否为"学生个人中心"来进行判断是否登录成功
                               if((m.group(1).toString()).equals("学生个人中心")){
                                       //登录成功的相应代码
                                }else{

                               }
                        }

                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}).start();

这时我们就已经完成了模拟登录,之后可以使用这个cookie访问管理系统的各个url了。

三、最终效果

效果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,454评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 最近做学校教务系统爬虫,这里写一下我遇到的一些问题和心得。 1.用到的工具 Chrome的开发者工具:分析网页行为...
    WeiHing阅读 2,356评论 0 5
  • 那年南下,过的不好。虽然不想承认... 的确,外人看来,表面的物质丰富或许会让我的内心稍许满足,而我,...
    杨大美的思念阅读 248评论 0 0
  • 事情过去已经快两年了,说句实话我从来都没有真正的走出来过。我只要一看见他我就会想起来,就像我跟我朋友说的一样,我们...
    密码箱阅读 353评论 0 2