You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整k6负载测试流程,解决Liferay JSONWS认证失败问题

解决Liferay 7.1中k6负载测试调用JSONWS API的认证问题

问题背景

在为Liferay 7.1的WebSocket端点构建k6负载测试时,模拟浏览器Cookie认证流程(登录→获取JWT→初始化WebSocket)遇到异常:调用JSONWS的my-app.auth/create-token接口时,Liferay日志报错[JSONAction:92] User 34253 must be authenticated,请求被重定向至/generic.html后陷入404循环。已确认k6正确传递JSESSIONID及其他Cookie,且使用与浏览器测试相同的用户。

问题排查与调整方案

1. 禁止硬编码p_auth令牌

Liferay的p_auth令牌是会话绑定且一次性有效,不能复用首页的csrfToken或硬编码固定值(如代码中的xt6uBXfx)。需从登录后的响应中重新提取最新的p_auth值,用于后续JWT请求。

2. 同步会话状态与重定向处理

k6默认跟随重定向,但Liferay登录后的多次重定向(/c/→/)可能导致会话状态未完全同步。可显式控制重定向行为,确保每次请求携带最新Cookie:

  • 使用redirects参数限制重定向次数,手动处理后续请求;
  • 登录完成后,提取响应中的所有Cookie更新到k6的Cookie Jar。

3. 模拟浏览器请求头

Liferay可能校验User-Agent、Referer等请求头字段,k6默认请求头与浏览器差异较大,易触发认证拦截。需为所有请求添加浏览器风格的请求头:

const browserHeaders = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
  'Referer': 'http://localhost:8080/web/guest/home',
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
};

4. 验证Cookie完整性

除JSESSIONID外,Liferay还依赖LFR_SESSION_STATE_*等系列Cookie。可登录后打印k6的Cookie Jar内容,对比浏览器Cookie列表,确保无遗漏:

console.log(JSON.stringify(http.cookieJar().getCookies('http://localhost:8080')));

调整后的完整k6测试脚本示例

import http from 'k6/http';
import { parseHTML } from 'k6/html';

export default function () {
  const username = 'test-user';
  const password = 'test-pass';
  const baseUrl = 'http://localhost:8080';
  const browserHeaders = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
    'Referer': `${baseUrl}/web/guest/home`,
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
  };

  // 1. 访问首页获取初始p_auth
  const homeResponse = http.get(`${baseUrl}/`, { headers: browserHeaders });
  const homeDoc = parseHTML(homeResponse.body);
  const initialCsrfToken = homeDoc.find('input[name="p_auth"]').first().attr('value');

  // 2. 执行登录请求
  const loginParams = {
    headers: { ...browserHeaders, 'Content-Type': 'application/x-www-form-urlencoded' },
    redirects: 2 // 显式控制重定向次数
  };
  const loginResponse = http.post(
    `${baseUrl}/web/guest/home?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_com_liferay_login_web_portlet_LoginPortlet_javax.portlet.action=%2Flogin%2Flogin&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Flogin`,
    {
      _com_liferay_login_web_portlet_LoginPortlet_formDate: Date.now(),
      _com_liferay_login_web_portlet_LoginPortlet_saveLastPath: "false",
      _com_liferay_login_web_portlet_LoginPortlet_redirect: "",
      _com_liferay_login_web_portlet_LoginPortlet_doActionAfterLogin: "false",
      _com_liferay_login_web_portlet_LoginPortlet_login: username,
      _com_liferay_login_web_portlet_LoginPortlet_password: password,
      _com_liferay_login_web_portlet_LoginPortlet_checkboxNames: "rememberMe",
      p_auth: initialCsrfToken,
    },
    loginParams
  );

  // 3. 提取登录后的最新p_auth
  const loginDoc = parseHTML(loginResponse.body);
  const postLoginCsrfToken = loginDoc.find('input[name="p_auth"]').first().attr('value');
  if (!postLoginCsrfToken) {
    throw new Error('Failed to retrieve post-login p_auth token');
  }

  // 4. 请求JWT
  const jwtResponse = http.get(
    `${baseUrl}/api/jsonws/my-app.auth/create-token?p_auth=${postLoginCsrfToken}`,
    { headers: browserHeaders }
  );

  // 验证结果
  if (jwtResponse.status !== 200) {
    console.log(`JWT请求失败: ${jwtResponse.status}, 响应内容: ${jwtResponse.body}`);
  } else {
    console.log('成功获取JWT');
  }
}

额外注意事项

  • 替换getFormDate()为Liferay期望的毫秒级时间戳;
  • 若Liferay开启严格CSRF校验,所有非静态资源请求都需携带正确的p_auth令牌;
  • 可通过k6 run -v script.js开启请求日志,对比浏览器请求详情定位差异点。

内容的提问来源于stack exchange,提问作者shawmanz32na

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:45:27