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

Gatling测试因Spring Security CSRF令牌导致POST请求403问题求助

解决Gatling测试中Spring Security CSRF令牌导致的403错误

搞定这个403问题其实很简单,核心就是让Gatling像浏览器一样先拿到Spring Security生成的CSRF令牌,再在POST请求里带上它。以下是具体的修改步骤:

1. 从表单页面提取CSRF令牌

你在访问/recherche/avancee/form时,页面里已经通过JSTL标签渲染了CSRF令牌(通常是隐藏表单字段或meta标签)。我们需要在这个GET请求中添加检查逻辑,把令牌提取出来并存入Gatling的Session中。

修改你的RechercheAvanceeForm请求部分:

.exec(
  http("RechercheAvanceeForm")
    .get("/recherche/avancee/form")
    .check(status.is(200))
    // 从页面的隐藏表单字段中提取_csrf值(Spring Security默认的存储方式)
    .check(css("input[name='_csrf']", "value").saveAs("csrfToken"))
    // 如果你的令牌是放在meta标签里的,替换成这行:
    // .check(css("meta[name='_csrf']", "content").saveAs("csrfToken"))
)

2. 在POST请求中携带CSRF令牌

提取到令牌后,只需要在POST请求的表单参数中添加_csrf字段,值引用刚才存入Session的csrfToken即可。

修改你的RechercheAvanceeAgentPost请求部分,新增一行formParam("_csrf", "${csrfToken}"):

.exec(
  http("RechercheAvanceeAgentPost")
    .post("/recherche/avancee/result")
    .headers(sentHeaders)
    .formParam("_csrf", "${csrfToken}") // 新增这一行,携带CSRF令牌
    .formParam("mrn.comparateur", "EGAL")
    .formParam("mrn.value", "")
    // 其他所有formParam保持不变...
    .check(status.is(200))
)

完整修改后的代码示例

val sentHeaders = Map(
  "Content-Type" -> "application/x-www-form-urlencoded",
  "User-Agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0",
  "Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  "Accept-Language" -> "fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3",
  "Connection" -> "keep-alive")

val rechercheAvanceeScn = scenario("RechercheAvanceeAgent").during(TestsPerfConfiguration.dureeTest, "RechercheAvanceeAgentDuration", true) {
  // Phase1: Authentification
  exec(
    http("Authentification")
      .get("/authlogin?sid=1&app=999&code_teleservice=DELTA-T"))
  // Phase 2: Form Recherche avancée
  .exec(
    http("RechercheAvanceeForm")
      .get("/recherche/avancee/form")
      .check(status.is(200))
      .check(css("input[name='_csrf']", "value").saveAs("csrfToken"))
  )
  // Phase 3: Recherche Avancée par type de declaration et type de garantie
  .exec(
    http("RechercheAvanceeAgentPost")
      .post("/recherche/avancee/result")
      .headers(sentHeaders)
      .formParam("_csrf", "${csrfToken}")
      .formParam("mrn.comparateur", "EGAL")
      .formParam("mrn.value", "")
      .formParam("typeDeclaration.value", "")
      .formParam("dateDebut.comparateur", "EGAL")
      .formParam("dateDebut.value", "")
      .formParam("dateDebut.valueMax", "")
      .formParam("dateLimitePresentationMarchandises.comparateur", "EGAL")
      .formParam("dateLimitePresentationMarchandises.value", "")
      .formParam("dateLimitePresentationMarchandises.valueMax", "")
      .formParam("modeTransmission.value", "TOUS")
      .formParam("typeProcedureDepart.value", "")
      .formParam("typeProcedureDestination.value", "")
      .formParam("dateFin.comparateur", "EGAL")
      .formParam("dateFin.value", "")
      .formParam("dateFin.valueMax", "")
      .formParam("dateDepotDeclaration.comparateur", "EGAL_HEURE_MINUTES")
      .formParam("dateDepotDeclaration.value", "")
      .formParam("heureDepotDeclaration.value", "00:00")
      .formParam("dateDepotDeclaration.valueMax", "")
      .formParam("heureDepotDeclaration.valueMax", "00:00")
      .formParam("donneesSureteSecurite.value", "")
      .formParam("paysExpedition.value", "")
      .formParam("nomenclatureMarchandises.comparateur", "EGAL")
      .formParam("nomenclatureMarchandises.value", "")
      .formParam("paysDestination.value", "")
      .formParam("valeurFactureTotale.comparateur", "EGAL")
      .formParam("valeurFactureTotale.value", "")
      .formParam("valeurFactureTotale.valueMax", "")
      .formParam("bureauDepart.value", "")
      .formParam("bureauDestination.value", "")
      .formParam("bureauPassage.value", "")
      .formParam("circuitBureauDepart.value", "")
      .formParam("resultatControlesDepart.value", "")
      .formParam("circuitBureauPassage.value", "")
      .formParam("resultatControlesPassage.value", "")
      .formParam("circuitBureauDestination.value", "")
      .formParam("resultatControlesDestination.value", "")
      .formParam("typeGarantie.value", "TYPE_1")
      .formParam("dateDebutGarantie.comparateur", "EGAL")
      .formParam("dateDebutGarantie.value", "")
      .formParam("dateDebutGarantie.valueMax", "")
      .formParam("montantDetteSusceptibleNaitre.comparateur", "EGAL")
      .formParam("montantDetteSusceptibleNaitre.value", "")
      .formParam("montantDetteSusceptibleNaitre.valueMax", "")
      .formParam("grn.comparateur", "EGAL")
      .formParam("grn.value", "")
      .formParam("dateFinGarantie.comparateur", "EGAL")
      .formParam("dateFinGarantie.value", "")
      .formParam("dateFinGarantie.valueMax", "")
      .formParam("_suiteNonLiberationService.booleanValue", "on")
      .formParam("_suiteControleGarantie.booleanValue", "on")
      .formParam("etatDeclaration.value", "VALIDEE_MRN")
      .formParam("result", "")
      .check(status.is(200))
  )
}

原理说明

Spring Security启用CSRF防护后,会对所有非GET的请求(比如POST)验证CSRF令牌的有效性。浏览器在访问表单页面时,会自动加载页面中的令牌并在提交表单时携带它。Gatling作为性能测试工具,需要手动模拟这个流程:先获取令牌,再在POST请求中带上,这样就能通过Spring Security的验证,避免403错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:27:41