• Android开发登陆博客园的正确方式


          首先吐点苦水,作者的博客园—Android客户端已经停止维护半年多了,明知登陆有问题但却没动力去改进,想使用MD规范+RxJava重构却苦于接口问题,实在太不规范,而且还不稳定...

          进入正题吧,第一种方法,JS注入登陆。

          首先我们看看下图博客园Web接口的登陆界面:简简单单,两个输入框,一个按钮

           

          检查一下它的属性:这里只看看密码这个属性,id="input2",用户名id="input1",登陆的id="signin"

           

           接下来就好办了,写一个这样的布局,非常简单:当然真正的开发界面不能这样丑,而且webview应该隐藏起来。

           

           

           获取两个EditText的输入文本为String name,pwd之后,我们为webview注入用户名密码,并触发登陆按钮click:

    
    
    默认加载这个页面,也就是登陆页面。
    1 webview.loadUrl("https://passport.cnblogs.com/user/signin?ReturnUrl=http%3A%2F%2Fwww.cnblogs.com%2F");
    2 String js = "javascript:document.getElementById('input1').setAttribute('value','" + name + "');" + "document.getElementById('input2').setAttribute('value','" + pwd + "');" + "document.getElementById('signin').click();"; 3 webview.loadUrl(js);
    
    
    

    这样就能登陆了。当然成功与否可以给webview添加client,然后在onPageFinished里面判断,然后获取cookie,这个cookie就能用来做各种用户操作了。

    第二种登陆方法:模拟登陆。第一种方法毕竟很繁琐,没什么技术含量,我们知道这个登陆接口是用到RSA加密的,只不过我们巧妙地避开了加密,直接拿到cookie而已。一起看看第二种加密方式吧:
    说到模拟登陆,首先就离不开抓包。不知为何,去年还能使用fiddler抓到登陆接口,现在却不行了,但是毕竟抓包工具这么多,还是有办法的。我们就是使用IE+HttpWatch来看看吧

    登陆界面的源码是这样的,很快就发现了公钥publicKey以及它的加密流程了,对用户名进行公钥加密,对密码进行公钥加密,还有个remenber=true|false,这是ajax登陆的json数据

       再往下看发现了VerificationToken这个头部,起初我以为它有什么用,便写个正则取出它的值:实际并没什么用处
    
    
    1  Pattern pattern = Pattern.compile("'VerificationToken'\s*:\s*'([^\s\n]+)'");
    2  Matcher matcher = pattern.matcher(s);
    
    
    
    
    
       我们继续抓包:输入用户名密码之后,打开Record记录,点击登陆:看到以下的数据:登陆接口+POST json的数据 {input1:"RSA加密的用户名",input2:"RSA加密的密码",remenber:true}

     
     切换到Headers看看里面的数据:


    如我们期待一般,有VerificationToken和Ajax异步请求的头部:X-Requested-With,还有两个重要的header,Content-Type和Cookie,AspxAutoDetectCookieSupport=1是固定的,
    SERVERID来自登陆界面,可自行获取,至此,我们要模拟登陆的流程和数据都搞清楚了。下面是模拟登陆的代码:使用AsyncHttpClient,没必要Retrofit或者OKHttp了。
     1 AsyncHttpClient client = new AsyncHttpClient();
     2 client.get("https://passport.cnblogs.com/user/signin?ReturnUrl=http%3A%2F%2Fwww.cnblogs.com%2F", new TextHttpResponseHandler() {
     3     @Override
     4     public void onFailure(int i, Header[] headers, String s, Throwable throwable) {
     5 
     6     }
     7 
     8     @Override
     9     public void onSuccess(int i, Header[] headers, String s) {
    10         String token = "";
    11         Pattern pattern = Pattern.compile("'VerificationToken'\s*:\s*'([^\s\n]+)'");
    12         Matcher matcher = pattern.matcher(s);
    13         if (matcher.find()) {
    14                 token = matcher.group(1);
    15         }
    16         String tmpcookies = "";
    17         for (Header header : headers) {
    18             String key = header.getName();
    19             String value = header.getValue();
    20             if (key.contains("Set-Cookie") && value.contains("SERVERID")) {
    21                 tmpcookies += value;
    22                 tmpcookies = tmpcookies.replace("Path=/", "");
    23             }
    24 
    25         }
    26         if (tmpcookies.length() > 0) {
    27             tmpcookies = "AspxAutoDetectCookieSupport=1;" + tmpcookies.substring(0, tmpcookies.length() - 1);
    28         }
    29         LoginBean bean = new LoginBean();//只有三个属性的Bean ,String类型的input1,input2,remenber boolean类型
    30         bean.setRemember(true);
    31         try {
    32             bean.setInput1(RSA.encrypt("huanghaibin_dev", RSA.KEY));//公钥加密
    33             bean.setInput2(RSA.encrypt("11111111", RSA.KEY));
    34             String json = new Gson().toJson(bean);
    35             ByteArrayEntity entity = null;
    36             entity = new ByteArrayEntity(json.getBytes("UTF-8"));         38             client.addHeader("Cookie", tmpcookies);
    39             client.addHeader("Content-Type", "application/json; charset=utf-8");
    40             //client.addHeader("VerificationToken", token);
    41             client.addHeader("X-Requested-With", "XMLHttpRequest");
    42             client.post(WelcomeActivity.this, "https://passport.cnblogs.com/user/signin", entity, "application/json; charset=UTF-8", new TextHttpResponseHandler() {
    43                 @Override
    44                 public void onFailure(int i, Header[] headers, String s, Throwable throwable) {
    45 
    46                 }
    47 
    48                 @Override
    49                 public void onSuccess(int i, Header[] headers, String s) {
    50                      //返回{success:true}这种类型的json
    51                 }
    52             });
    53         } catch (Exception e) {
    54             e.printStackTrace();
    55         }
    56     }
    57 });

    RSA加密
    
    
     1 public static PublicKey getPublicKey(String key) throws Exception {
     2     X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
     3             Base64.decode(key.getBytes(),Base64.DEFAULT));
     4     KeyFactory keyFactory = KeyFactory.getInstance("RSA");
     5     PublicKey publicKey = keyFactory.generatePublic(keySpec);
     6     return publicKey;
     7 }
     8 
     9 public static String encrypt(String source, String publicKey)
    10         throws Exception {
    11     Key key = getPublicKey(publicKey);
    12     /** 得到Cipher对象来实现对源数据的RSA加密 */
    13     Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    14     cipher.init(Cipher.ENCRYPT_MODE, key);
    15     byte[] b = source.getBytes();
    16     /** 执行加密操作 */
    17     byte[] b1 = cipher.doFinal(b);
    18     return new String(Base64.encode(b1,Base64.DEFAULT),
    19             ConfigureEncryptAndDecrypt.CHAR_ENCODING);
    20  }
    
    
    


  • 相关阅读:
    yarn之安装依赖包
    Yarn 的工作流-创建一个新项目
    yarn使用
    yarn安装
    用yarn替代npm
    搭建开发环境
    网页瞬间转换成桌面应用级程序(IOS/Win/Linux)
    [转]js模块化编程之彻底弄懂CommonJS和AMD/CMD!
    Node.js模块导出exports 和 module.exports 的区别
    Javascript modules--js 模块化
  • 原文地址:https://www.cnblogs.com/huanghaibin/p/5803325.html
Copyright © 2020-2023  润新知