前言

我们在进行接口自动化工作时,业务接口往往需要权限验证才能调通,所以首先需调用登录接口,登录成功后,拿到该接口返回的 Token,但由于有的 Web 系统不能通过接口获取到 Token,所以只能先手动打开浏览器->输入账号密码->点击登录->打开 F12 拿到 Token,再复制粘贴到调用接口所需要的参数中,若 Token 设置了有效期,则要反复执行次步骤,导致接口自动化也没有很自动,以下介绍此类问题的解决方法。

解决思路

使用 Selenium 打开系统登录页面,输入账号密码,登录成功后抓包,拿到可以获取 Token 的接口,并将抓到 Token 存到数据库或存到本地文件中。之后请求接口时,先读取 Token,再传递到请求参数中。

工具

BrowserMobProxy 一款基于 Java 的代理服务,类似我们使用的 Fiddler,即开启一个端口并作为一个标准代理存在,当 HTTP 客户端(浏览器等)设置了这个代理,则抓取并有能力修改所有的请求细节并获取返回内容。支持 Java、Python。

代码讲解

初始化 BrowserMobProxy(相当于打开 Fiddler)


BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
browserMobProxy.start();
browserMobProxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
browserMobProxy.setHarCaptureTypes(CaptureType.RESPONSE_CONTENT);
browserMobProxy.newHar("qym");
Proxy seleniumProxy = ClientUtil.createSeleniumProxy(browserMobProxy);
// 设置浏览器参数
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability(CapabilityType.PROXY,seleniumProxy);
ChromeOptions options = new ChromeOptions();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS,true);
capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS,true);

初始化 WebDriver 并打开浏览器访问 Web 系统


WebDriver driver = new ChromeDriver(capabilities);
//打开链接
driver.get("https://***-***-ccms.***.com/portal/index.html#/***");
driver.manage().window().maximize();
Thread.sleep(500);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

由于 Selenium 每次打开一个浏览器窗口,都是没有 Cookie 的窗口,相当于 Chrome 的无痕模式,但本 Web 系统使用新浏览器访问时,需要输入手机验证码,对于自动化来说,会比较麻烦,估而采取以下方式,首先打开之前访问过该网站的浏览器,输入 url,打开该网页拿到 Cookie(Chrome:F12->点击 Application->找到左侧 Storage 一栏中 Cookie,拿到所需的数据),使用 Cookie 注入的方式,在每次 Selenium 打开浏览器时,将 Cookie 注入到浏览器中。这样就不需要再输入手机验证码。

Cookie c1 = new Cookie("_ati","***");
Cookie c2 = new Cookie("x_session","***");
Cookie c3 = new Cookie("tenantId","***");
Cookie c4 = new Cookie("sy-cook","***");
Cookie c5 = new Cookie("***.***.com","***");
Cookie c6 = new Cookie("acw_tc","***");
Cookie c7 = new Cookie("SDPID","***.***.Xaf5htP0Jd_B8IZnErSLlc7Emfv3--8hewnhs6irL5U");
Cookie c8 = new Cookie("JSESSIONID","***.***.***--8hewnhs6irL5U");
Cookie c9 = new Cookie("ccmsRequestCredential","***");
Thread.sleep(500);
driver.manage().addCookie(c1);
System.out.println(""+c1);
driver.manage().addCookie(c2);
driver.manage().addCookie(c3);
driver.manage().addCookie(c4);
driver.manage().addCookie(c5);
driver.manage().addCookie(c6);
driver.manage().addCookie(c7);
driver.manage().addCookie(c8);
driver.manage().addCookie(c9);
driver.navigate().refresh();
Thread.sleep(500);
driver.get("https://***-***-ccms.***.com/portal/index.html#/***");
List<WebElement> ButtonElement = driver.findElements(By.className("***-input"));
ButtonElement.get(0).sendKeys("**************");
ButtonElement.get(1).sendKeys("***@***");
driver.findElement(By.id("btn")).click();
Thread.sleep(500);

此时 BrowserMobProxy 已经拿到了以上步骤访问过的接口,存到了 Har,但抓到的接口众多,并不是每个接口都返回了 Token,所以需要先手动筛选能返回 Token 的接口,找到该接口,并拿到该接口返回的 Json,获取到 json 中存在 Token 的 Key、Value,拿到 Token,并写入到本地文件中供后续接口自动化过程使用。

Har har = browserMobProxy.getHar();
     List<HarEntry> entries = har.getLog().getEntries();
     for (HarEntry harEntry : entries) {
         String url = harEntry.getRequest().getUrl();
         HarResponse response = harEntry.getResponse();
         String conent = response.getContent().getText();
         if (url.contains("/***")){
             JSONObject jsonObject = JSONObject.parseObject(conent);
             System.out.println(jsonObject.get("id"));
             TokenFile.witerFile((String) jsonObject.get("id"),"E:\\JavaCode\\AllureTest\\src\\main\\java\\Token.txt");
             break;
         }
     }

关闭浏览器窗口,由于此 Web 系统会弹出新窗口,若只使用 driver.close() 只能关掉当前窗口,不能关闭所有窗口,所以要拿到所有已打开浏览器的窗口,逐个关闭。

Set<String> handles = driver.getWindowHandles();
    String CurlHandle =driver.getWindowHandle();
    for(String s: handles) {
        if (s.equals(CurlHandle)) {
            driver.close();
            continue;
        } else {
            driver.switchTo().window(s);
            driver.close();
        }
    }

以下是完整代码


public class GetToken {
    public static void main(String[] args) throws InterruptedException {
        testProxy();
    }
    public static void testProxy() throws InterruptedException {
         //初始化browserMobProxy 
        BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
        browserMobProxy.start();
        browserMobProxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
        browserMobProxy.setHarCaptureTypes(CaptureType.RESPONSE_CONTENT);
        browserMobProxy.newHar("qym");
        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(browserMobProxy);
        // 设置浏览器参数
        DesiredCapabilities capabilities = DesiredCapabilities.chrome();
        capabilities.setCapability(CapabilityType.PROXY,seleniumProxy);
        ChromeOptions options = new ChromeOptions();
        capabilities.setCapability(ChromeOptions.CAPABILITY, options);
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS,true);
        capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS,true);
        // 创建驱动对象
        WebDriver driver = new ChromeDriver(capabilities);
        //打开链接
        driver.get("https://qa-***-***.***.com/portal/index.html#/***");
        driver.manage().window().maximize();
        Thread.sleep(500);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        Thread.sleep(500);

        Cookie c1 = new Cookie("_ati","***");
        Cookie c2 = new Cookie("x_session","***");
        Cookie c3 = new Cookie("tenantId","***");
        Cookie c4 = new Cookie("sy-cook","***");
        Cookie c5 = new Cookie("***.******.com","***");
        Cookie c6 = new Cookie("acw_tc","***");
        Cookie c7 = new Cookie("SDPID",".***");
        Cookie c8 = new Cookie("JSESSIONID","***");
        Cookie c9 = new Cookie("ccmsRequestCredential","***");
        Thread.sleep(500);
        driver.manage().addCookie(c1);
        System.out.println(""+c1);
        driver.manage().addCookie(c2);
        driver.manage().addCookie(c3);
        driver.manage().addCookie(c4);
        driver.manage().addCookie(c5);
        driver.manage().addCookie(c6);
        driver.manage().addCookie(c7);
        driver.manage().addCookie(c8);
        driver.manage().addCookie(c9);
        driver.navigate().refresh();
        Thread.sleep(500);
        driver.get("https://qa-***ccms.****.com/portal/index.html#/customerGrouping");
        List<WebElement> ButtonElement = driver.findElements(By.className("cloud-input"));
        ButtonElement.get(0).sendKeys("***.****");
        ButtonElement.get(1).sendKeys("****@***");
        driver.findElement(By.id("btn")).click();
        Thread.sleep(500);
        List<WebElement> ButtonElement2 = driver.findElements(By.className("***"));
        ButtonElement2.get(0).click();
        Thread.sleep(1000);
        // 获取返回的请求内容
        Har har = browserMobProxy.getHar();
        List<HarEntry> entries = har.getLog().getEntries();
        for (HarEntry harEntry : entries) {
            String url = harEntry.getRequest().getUrl();
            HarResponse response = harEntry.getResponse();
            String conent = response.getContent().getText();
            if (url.contains("/web-***/***/***")){
                JSONObject jsonObject = JSONObject.parseObject(conent);
                System.out.println(jsonObject.get("id"));
                TokenFile.witerFile((String) jsonObject.get("id"),"E:\\JavaCode\\AllureTest\\src\\main\\java\\Token.txt");
                break;
            }
        }
        Set<String> handles = driver.getWindowHandles();
        String CurlHandle =driver.getWindowHandle();
        for(String s: handles) {
            if (s.equals(CurlHandle)) {
                driver.close();
                continue;
            } else {
                driver.switchTo().window(s);
                driver.close();
            }
        }
        System.exit(0);
    }
}


↙↙↙阅读原文可查看相关链接,并与作者交流