Spring Boot 3中如何重写Spring Security的CSRF生成逻辑?
Spring Boot 3.x 自定义 CSRF Token 生成逻辑失效问题解决
问题核心原因
- 包路径变更:Spring Boot 3.x 基于 Jakarta EE,所有 Servlet 相关类从
javax.servlet.http迁移到了jakarta.servlet.http,自定义实现类必须使用新包路径,否则会因类不兼容导致逻辑不生效。 - 默认校验规则:Spring Security 6.x(对应 Boot 3.x)默认不对
GET/HEAD/TRAC/OPTIONS请求做 CSRF 校验,因此访问 GET 接口/hello时不会触发loadToken方法,这是框架默认行为,而非代码失效。
分步解决方案
1. 修正自定义 Repository 的包依赖与实现
确保 CustomCsrfTokenRepository 导入正确的 Jakarta Servlet 包,同时补全方法的有效返回值(原代码中 generateToken 无返回值会导致编译错误):
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.security.web.csrf.DefaultCsrfToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CustomCsrfTokenRepository implements CsrfTokenRepository { private static final Logger log = LoggerFactory.getLogger(CustomCsrfTokenRepository.class); @Override public CsrfToken generateToken(HttpServletRequest request) { log.info("执行 generateToken"); // 返回标准 CsrfToken 实例,可自定义 Token 值与头部名称 return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "custom-generated-token"); } @Override public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) { log.info("执行 saveToken"); // 实现 Token 持久化逻辑,比如存入 Session 或 Cookie } @Override public CsrfToken loadToken(HttpServletRequest request) { log.info("执行 loadToken"); // 实现 Token 读取逻辑,从存储介质中获取 return null; // 根据实际业务返回对应 Token } }
2. 按需调整 CSRF 校验规则
如果需要让 GET 请求也触发 CSRF 校验(默认不触发),可在 Security 配置中自定义校验匹配器;若仅需校验修改类请求(POST/PUT/DELETE),则保持默认规则即可。
配置示例(包含 GET 校验):
@Configuration @EnableWebSecurity public class ProjectConfig { @Bean public CsrfTokenRepository customTokenRepository() { return new CustomCsrfTokenRepository(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf .csrfTokenRepository(customTokenRepository()) // 自定义需要校验的请求方法,这里包含 GET .requireCsrfProtectionMatcher(request -> { String method = request.getMethod(); return "GET".equals(method) || "POST".equals(method) || "PUT".equals(method) || "DELETE".equals(method); }) ) .authorizeHttpRequests(auth -> auth .anyRequest().permitAll() ); return http.build(); } }
3. 验证逻辑有效性
- 若使用默认规则:测试 POST/PUT/DELETE 请求,此时会自动触发 CSRF 校验,自定义 Repository 的
loadToken等方法会执行。 - 若配置了 GET 校验:访问
/helloGET 接口时,loadToken方法会被调用。
内容的提问来源于stack exchange,提问作者hhrzc
相关产品推荐
相关产品推荐

