Spring WebSecurityConfigurerAdapter中配置CORP头特定路径例外
解决Spring Security特定路径移除Cross-Origin-Resource-Policy头的问题
问题场景
我们基于Spring Security的WebSecurityConfigurerAdapter配置安全头,核心代码中为所有请求添加了Cross-Origin-Resource-Policy: SAME_ORIGIN头,确保非同源请求无法加载资源,符合预期。但现在需要为/public_resources/**路径设置例外:保留该路径的其他所有安全头,仅移除Cross-Origin-Resource-Policy头,且网站域名是动态生成的,无法硬编码。
之前尝试的两种方法均无效:
- 在
configure方法末尾添加antMatches配置StaticHeadersWriter,意外覆盖了其他路径的安全头; - 创建独立的
WebSecurityConfigurerAdapter子类配置例外,未生效。
使用环境:spring-framework.version 5.3.39;spring-boot-starter-parent 2.7.18;JDK 21。
有效解决方案
方案一:自定义HeaderWriter(推荐,无需重复配置安全头)
通过扩展CrossOriginResourcePolicyHeaderWriter,根据请求路径判断是否写入Cross-Origin-Resource-Policy头,避免重复配置所有安全头。
- 实现自定义HeaderWriter:
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter; import org.springframework.web.util.AntPathMatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class PathExcludingCORPHeaderWriter extends CrossOriginResourcePolicyHeaderWriter { private final AntPathMatcher pathMatcher = new AntPathMatcher(); private final String excludedPathPattern; public PathExcludingCORPHeaderWriter(CrossOriginResourcePolicy policy, String excludedPathPattern) { super(policy); this.excludedPathPattern = excludedPathPattern; } @Override public void writeHeaders(HttpServletRequest request, HttpServletResponse response) { // 仅当请求路径不匹配排除规则时,才写入CORP头 if (!pathMatcher.match(excludedPathPattern, request.getRequestURI())) { super.writeHeaders(request, response); } } }
- 修改原SecurityConfig配置:
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 保留原有其他安全头配置 http.headers() // 示例:其他安全头配置(根据你的实际需求调整) .contentTypeOptions() .and() .xssProtection() .and() .frameOptions() // 替换原有的crossOriginResourcePolicy配置为自定义HeaderWriter .and() .addHeaderWriter(new PathExcludingCORPHeaderWriter( CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN, "/public_resources/**" )) .and() // 其他HttpSecurity配置... .authorizeRequests() .anyRequest().authenticated(); } }
方案二:多HttpSecurity配置(需同步安全头配置)
创建两个优先级不同的WebSecurityConfigurerAdapter子类,分别处理公共资源路径和全局路径,确保公共资源路径的配置先被匹配。
- 公共资源路径配置(高优先级):
import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @Configuration @Order(1) // 优先级高于全局配置,确保先匹配 public class PublicResourcesSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .requestMatchers() .antMatchers("/public_resources/**") .and() .headers() // 同步全局配置中的所有安全头,除了禁用CORP头 .contentTypeOptions() .and() .xssProtection() .and() .frameOptions() // 禁用CORP头的自动添加 .and() .crossOriginResourcePolicy().disable() .and() // 其他安全头配置(与全局保持一致) .and() // 公共资源路径的授权规则(根据实际需求调整) .authorizeRequests() .antMatchers("/public_resources/**").permitAll(); } }
- 全局路径配置:
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter; @Configuration @EnableWebSecurity public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .headers() // 配置所有安全头,包括CORP .contentTypeOptions() .and() .xssProtection() .and() .frameOptions() .and() .crossOriginResourcePolicy() .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN) .and() // 其他安全头配置 .and() // 全局授权规则 .authorizeRequests() .anyRequest().authenticated(); } }
原方法无效原因说明
- StaticHeadersWriter覆盖问题:
StaticHeadersWriter是设置固定的响应头集合,会直接替换原有头配置,导致其他安全头丢失,而非仅移除特定头。 - 独立配置未生效:未给独立配置类添加
@Order注解,导致全局配置先被匹配,覆盖了例外规则;或者例外配置中未同步全局的安全头配置,导致公共资源路径丢失其他安全头。
内容的提问来源于stack exchange,提问作者Kevin Cruijssen
相关产品推荐
相关产品推荐

