Spring Security添加路径变量校验过滤器的实现方法咨询
Spring Security 自定义过滤器实现路径编码校验方案
我刚好做过类似的需求,给你一套清晰的实现步骤,保证能在请求碰着Controller之前就完成校验,直接返回400错误,完全符合你的要求:
1. 编写自定义校验过滤器
先创建一个继承OncePerRequestFilter的过滤器——这个类是Spring官方提供的,能确保每个请求只会被过滤一次,特别适合这种前置校验的场景。
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.util.AntPathMatcher; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Map; public class RegionCodeValidationFilter extends OncePerRequestFilter { // 用Spring的路径匹配器提取路径里的变量,比自己拆字符串靠谱多了 private final AntPathMatcher pathMatcher = new AntPathMatcher(); // 如果你的校验逻辑需要调用其他服务(比如查数据库拿合法编码列表),可以在这里注入依赖 // private final RegionCodeValidator codeValidator; // 构造函数注入依赖(如果有的话) // public RegionCodeValidationFilter(RegionCodeValidator codeValidator) { // this.codeValidator = codeValidator; // } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 定义需要校验的路径模式,比如所有带国家码/地区码的REST接口 String targetPathPattern = "/{countryCode}/{regionCode}/**"; // 先判断当前请求路径是否符合我们要校验的模式 if (pathMatcher.match(targetPathPattern, request.getRequestURI())) { // 提取路径里的国家码和地区码 Map<String, String> pathVars = pathMatcher.extractUriTemplateVariables(targetPathPattern, request.getRequestURI()); String countryCode = pathVars.get("countryCode"); String regionCode = pathVars.get("regionCode"); // 这里替换成你的实际校验逻辑:对比路径编码和本地编码是否一致 // 比如本地编码是从请求头拿的,或者是服务端预定义的合法列表 if (!isValidCodeCombination(countryCode, regionCode)) { // 校验不通过,直接返回400 response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("application/json"); response.getWriter().write("{\"error\": \"无效的国家/地区编码组合\"}"); return; // 终止过滤链,不让请求继续往下走 } } // 校验通过,放行到后续过滤器和Controller filterChain.doFilter(request, response); } // 模拟你的编码校验逻辑,记得换成真实业务规则 private boolean isValidCodeCombination(String countryCode, String regionCode) { // 示例:只允许中国(CN)上海(SH)的编码组合 return "CN".equals(countryCode) && "SH".equals(regionCode); } }
2. 将过滤器注册到Spring Security过滤链
接下来要把这个过滤器加到Spring Security的流程里,关键是选对顺序——必须在请求到Controller之前执行,同时要和表单认证的过滤器配合好:
方式1:使用SecurityFilterChain(Spring Boot 2.7+ 官方推荐)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class SecurityConfig { // 如果过滤器需要依赖注入,用构造函数或者@Autowired注入 // private final RegionCodeValidationFilter regionCodeValidationFilter; // public SecurityConfig(RegionCodeValidationFilter regionCodeValidationFilter) { // this.regionCodeValidationFilter = regionCodeValidationFilter; // } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 保留你原有的表单认证配置 .formLogin(form -> form .loginPage("/login") .permitAll() ) // 保留你原有的授权规则 .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() ) // 把自定义过滤器加到表单认证过滤器之前,确保所有请求先过编码校验 .addFilterBefore(regionCodeValidationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } // 把自定义过滤器注册成Spring Bean,方便依赖注入和生命周期管理 @Bean public RegionCodeValidationFilter regionCodeValidationFilter() { return new RegionCodeValidationFilter(); // 如果有校验服务依赖,就传进去:return new RegionCodeValidationFilter(codeValidator); } }
方式2:使用WebSecurityConfigurerAdapter(旧版兼容)
如果你的项目还在使用旧版配置,可以这么加:
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.beans.factory.annotation.Autowired; public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private RegionCodeValidationFilter regionCodeValidationFilter; @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); // 把自定义过滤器放在表单认证过滤器之前 http.addFilterBefore(regionCodeValidationFilter, UsernamePasswordAuthenticationFilter.class); // 其他原有配置... } }
3. 几个关键注意点
- 过滤器顺序:用
addFilterBefore把校验放在表单认证之前,能确保所有请求(包括登录请求)都先过编码校验;如果只需要对已认证的请求做校验,可以把过滤器放在UsernamePasswordAuthenticationFilter之后。 - 路径匹配灵活性:
AntPathMatcher支持各种复杂路径模式,比如/api/{countryCode}/**这种,完全能适配你的路径规则。 - 错误返回效率:直接通过
HttpServletResponse返回400比抛异常再用全局异常处理器处理更高效,适合这种简单的参数校验场景。 - 依赖注入:如果校验逻辑需要调用其他服务,一定要把过滤器注册成Spring Bean,这样才能正常注入依赖。
这样配置完,所有符合路径模式的请求都会先经过编码校验,不符合规则的直接返回400,根本到不了Controller层,完美满足你的需求。
内容的提问来源于stack exchange,提问作者Dharita Chokshi
相关产品推荐
相关产品推荐

