Spring Security 6中使用MockMvc实现推荐CSRF保护的配置问题
解决方案
针对你遇到的Spring Security CSRF测试问题,这里提供两种可行方案:
方案一:手动生成CSRF Token并通过Header传递
在测试类中直接利用CsrfTokenRepository生成符合要求的Token,避免依赖端点获取,步骤如下:
- 确保测试类加载完整的Security配置和目标控制器
@WebMvcTest(YourTargetController.class) @Import(SecurityConfig.class) // 导入你的Spring Security配置类 class YourControllerTest { @Autowired private MockMvc mockMvc; @Autowired private CsrfTokenRepository csrfTokenRepository; @Test void postRequestWithCsrfHeader() throws Exception { // 生成CSRF Token并模拟存储逻辑 MockHttpServletRequest request = new MockHttpServletRequest(); CsrfToken csrfToken = csrfTokenRepository.generateToken(request); request.setAttribute(CsrfToken.class.getName(), csrfToken); csrfTokenRepository.saveToken(csrfToken, request, new MockHttpServletResponse()); // 发起POST请求,携带Header和Cookie mockMvc.perform(post("/") .header(csrfToken.getHeaderName(), csrfToken.getToken()) .cookie(new Cookie(csrfToken.getCookieName(), csrfToken.getToken()))) .andExpect(status().is2xxSuccessful()); } }
方案二:修复/csrf端点测试无法获取Cookie的问题
如果坚持通过/csrf端点获取Token,需确保测试类加载了该端点和完整的Security配置:
- 调整测试类的注解范围
@WebMvcTest({YourTargetController.class, CsrfTokenRestController.class}) @Import(SecurityConfig.class) class YourControllerTest { @Autowired private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @Test void postRequestWithCsrfFromEndpoint() throws Exception { // 请求/csrf端点获取Token和Cookie MvcResult csrfResult = mockMvc.perform(get("/csrf")) .andExpect(status().isOk()) .andReturn(); // 提取XSRF-TOKEN Cookie Cookie xsrfCookie = csrfResult.getResponse().getCookie("XSRF-TOKEN"); // 从响应体解析Token(也可直接用Cookie的值) CsrfToken token = objectMapper.readValue(csrfResult.getResponse().getContentAsString(), CsrfToken.class); // 发起POST请求 mockMvc.perform(post("/") .header("X-XSRF-TOKEN", xsrfCookie.getValue()) .cookie(xsrfCookie)) .andExpect(status().is2xxSuccessful()); } }
关键配置检查
确保你的Security配置正确启用了Cookie-based CSRF保护:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) // 允许前端读取Cookie ) // 其他安全配置... return http.build(); } }
Spring Rest Docs 补充说明
如果不想让CSRF Token出现在文档的请求参数中,可通过Rest Docs忽略参数:
this.mockMvc.perform(post("/")) .andDo(document("post-endpoint", requestParameters( parameterWithName("_csrf").ignored() ) ));
或者直接在文档中说明:请求需携带X-XSRF-TOKEN请求头,同时客户端需持有XSRF-TOKEN Cookie。
内容的提问来源于stack exchange,提问作者Wim Deblauwe
相关产品推荐
相关产品推荐

