美文网首页程序员@IT·互联网
Android模拟登录教务系统

Android模拟登录教务系统

作者: JACoder | 来源:发表于2018-02-20 19:26 被阅读0次

    一、原理

    • 在超级课程表等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了。

    三、最终效果

    效果

    相关文章

      网友评论

        本文标题:Android模拟登录教务系统

        本文链接:https://www.haomeiwen.com/subject/aipgtftx.html