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
相关产品推荐
相关产品推荐

