java模拟登录TpLink路由器,获取连接WIFI的设备列表

作者: ʘᴗʘ发布时间:2022-11-16 21:22 浏览量:300 点赞:237 售价:0

功能描述

最近在折腾小米米家的智能设备,其中有个特别想实现的功能:所有人离开家后,自动关闭家里的所有灯。实现这个功能的前置条件就是,能够自动登录TpLink路由器的后台,获取到当前连接WIFI的设备列表。

通过分析TpLink路由器的请求规则,发现步骤很简单,只要登录后,会有一个类似Token的字符串,后面的请求只要携带该字符串,即可正常拉取所有数据。

我的路由器型号是:TL-WDR7660

实现步骤

  1. 登录:TpLink路由器现在的登录很简单,账号都不用了,直接输入密码就行。但是这里的密码被TpLink登录页面的JS加密过了,所以你需要正常输入密码登录一次,然后通过浏览器的网络请求分析,把加密过的字符串复制出来。如下图所示:
    java模拟登录TpLink路由器,获取连接WIFI的设备列表
  2. 请求数据:登录完成后,你就可以去请求自己想要的数据了。不同的数据来源于不同的请求URL,根据你的需求,自己去TpLink的管理后台,通过Chrome等浏览器去抓取请求URL和方式。这里是我抓取的WIFI设备列表,我把返回结果用JSON展示:java模拟登录TpLink路由器,获取连接WIFI的设备列表

代码展示

核心代码只有一个Java的类,里面两个静态方法,一个登录,一个用来抓取WIFI设备列表。

其中用到了一个名为OkHttpUtil的类,是我自己封装的OKhttp网络请求框架,后面一起放出来。

核心代码

package com.coderbbb.homeiot.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class WirelessRouterUtil {

    //路由器管理后台地址。常见的为192.168.0.1或者192.168.1.1
    private static final String BASE_URL = "http://192.168.1.1/";

    //登录Token
    private static String STOK = null;

    private static final Logger logger = LoggerFactory.getLogger(WirelessRouterUtil.class);

    public static void login() {

        if (STOK != null) {
            return;
        }

        String json = "{\"method\":\"do\",\"login\":{\"password\":\"4i123这里是前面抓取的,加密后的密码ewK\"}}";

        String response = OkhttpUtil.postRaw(BASE_URL, "application/json; charset=UTF-8", json, null);
        if (response == null) {
            throw new RuntimeException("tplink login err");
        }
        try {
            JsonNode jsonNode = ObjectMapperUtil.get().readTree(response);
            if (jsonNode.has("error_code") && jsonNode.get("error_code").asInt() == 0) {
                STOK = jsonNode.get("stok").asText();
                logger.info("login tplink success, stok:" + STOK);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取路由器上的WIFI设备列表
     * @return
     */
    public static List<JsonNode> getDeviceList() {
        login();
        String json = "{\"hosts_info\":{\"table\":\"host_info\",\"name\":\"cap_host_num\"},\"network\":{\"name\":\"iface_mac\"},\"hyfi\":{\"table\":[\"connected_ext\"]},\"method\":\"get\"}";
        String url = BASE_URL + "stok=" + STOK + "/ds";
        String response = OkhttpUtil.postRaw(url, "application/json; charset=UTF-8", json, null);
        if (response == null) {
            throw new RuntimeException("tplink list devices err");
        }
//        System.out.println(response);
        try {
            List<JsonNode> devicesData = new ArrayList<>();
            JsonNode jsonNode = ObjectMapperUtil.get().readTree(response);
            if (jsonNode.has("error_code") && jsonNode.get("error_code").asInt() == 0) {
//                System.out.println("list success");
                JsonNode deviceListJson = jsonNode.get("hosts_info").get("host_info");
                for (JsonNode node : deviceListJson) {
                    devicesData.add(node.get(node.fieldNames().next()));
                }
            }
            System.out.println(devicesData);
            return devicesData;
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        getDeviceList();
    }

}

工具类OkHttpUtil

下面的代码中,只有postRaw方法是对本文有用的,其他的你可以注释掉。这是我自己封装的OKhttp请求类。

package com.coderbbb.homeiot.utils;

import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


public class OkhttpUtil {

    private static OkHttpClient client = null;

    private static final Logger logger = LoggerFactory.getLogger(OkhttpUtil.class);

    private synchronized static void createClient() {
        if (client == null) {
            OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();

            okHttpBuilder.protocols(Collections.singletonList(Protocol.HTTP_1_1));
            okHttpBuilder.connectTimeout(60, TimeUnit.SECONDS);
            okHttpBuilder.readTimeout(60, TimeUnit.SECONDS);
            okHttpBuilder.writeTimeout(60, TimeUnit.SECONDS);
            okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    //支持所有类型https请求
                    return true;
                }
            });

            ConnectionPool pool = new ConnectionPool(200, 1, TimeUnit.SECONDS);
            okHttpBuilder.connectionPool(pool);

            client = okHttpBuilder.build();
            client.dispatcher().setMaxRequests(2000);
            client.dispatcher().setMaxRequestsPerHost(1000);
        }
    }

    public static OkHttpClient getClient() {
        if (client == null) {
            createClient();
        }
        return client;
    }

    public static String get(String url, HashMap<String, String> headerMap) {
        Request.Builder builder = new Request.Builder().url(url);

        if (headerMap != null) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();

        String result = null;
        try {
            result = excute(request);
        } catch (Exception e) {
            logger.warn("http get fail:" + url + "###" + e.getMessage());
        }
        return result;
    }

    public static Response getAdvance(String url, HashMap<String, String> headerMap) throws Exception{
        Request.Builder builder = new Request.Builder().url(url);

        if (headerMap != null) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();
        return getClient().newCall(request).execute();
    }

    public static String postRaw(String url, String contentType, String json, HashMap<String, String> headerMap) {
        RequestBody requestBody = RequestBody.create(json,MediaType.parse(contentType));

        Request.Builder builder = new Request.Builder().url(url).post(requestBody);
        if (headerMap != null) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.build();
        String result = null;
        try {
            result = excute(request);
        } catch (Exception e) {
            logger.error("http post raw fail:" + url + "###" + e.getMessage());
        }
        return result;
    }

    public static String post(String url, HashMap<String, String> data, HashMap<String, String> headerMap) {

        FormBody.Builder formBodyBuilder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : data.entrySet()) {
            formBodyBuilder.add(entry.getKey(), entry.getValue());
        }
        RequestBody requestBody = formBodyBuilder.build();

        Request.Builder builder = new Request.Builder().url(url).post(requestBody);
        for (Map.Entry<String, String> entry : headerMap.entrySet()) {
            builder.addHeader(entry.getKey(), entry.getValue());
        }
        Request request = builder.build();
        String result = null;
        try {
            result = excute(request);
        } catch (Exception e) {
            logger.error("http post fail:" + url + "###" + e.getMessage());
        }
        return result;
    }

    private static String excute(Request request) throws Exception {
        try (Response response = getClient().newCall(request).execute()) {
            try (ResponseBody body = response.body()) {
                if (body != null) {
                    String str = body.string();

//                    if(!response.headers("miot-content-encoding").isEmpty()){
//                        System.out.println("miot-content-encoding=" + response.headers("miot-content-encoding"));
//                    }

                    body.close();
                    response.close();
                    return str;
                }
            }catch (Exception e){
                throw new Exception(e);
            }
        }catch (Exception e){
            throw new Exception(e);
        }
        return null;
    }
}

版权声明:《java模拟登录TpLink路由器,获取连接WIFI的设备列表》为CoderBBB作者「ʘᴗʘ」的原创文章,转载请附上原文出处链接及本声明。

原文链接:https://www.coderbbb.com/articles/70

其它推荐:

user

ʘᴗʘ

77
文章数
67049
浏览量
53263
获赞数
67.80
总收入