Spring Boot 3.1.0如何为特定路径配置带不同参数的过滤器
Spring Boot 3.1.0 配置路径专属JWT角色过滤器
你当前的代码中,两个AuthenticationFilter实例被全局添加到过滤器链中,没有限定生效路径,所以所有请求都会依次经过这两个过滤器,这就是/api/admins/get和/api/users/get都会触发两个过滤器执行的原因。以下是两种可行的解决方案:
方法一:使用FilterRegistrationBean注册路径专属过滤器
通过FilterRegistrationBean将过滤器注册为Spring Bean,并指定各自生效的URL模式,让过滤器只处理匹配的请求路径。
修改SecurityConfig配置
@RequiredArgsConstructor @Configuration @EnableWebSecurity public class SecurityConfig { private final JwtService jwtService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .cors(cors -> cors.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/users/**", "/api/admins/**").authenticated() .anyRequest().permitAll()); return http.build(); } // 注册用户路径的过滤器 @Bean public FilterRegistrationBean<AuthenticationFilter> userAuthenticationFilter() { FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new AuthenticationFilter(jwtService, List.of("USER", "ADMIN"))); registrationBean.addUrlPatterns("/api/users/**"); // 设置过滤器顺序,确保在BasicAuthenticationFilter之前执行 registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); return registrationBean; } // 注册管理员路径的过滤器 @Bean public FilterRegistrationBean<AuthenticationFilter> adminAuthenticationFilter() { FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new AuthenticationFilter(jwtService, List.of("ADMIN"))); registrationBean.addUrlPatterns("/api/admins/**"); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); return registrationBean; } }
完善AuthenticationFilter的验证逻辑
@RequiredArgsConstructor public class AuthenticationFilter implements Filter { private final JwtService jwtService; private final List<String> requiredRoles; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 从请求头获取JWT令牌 String authHeader = httpRequest.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "缺少或无效的Authorization请求头"); return; } String token = authHeader.substring(7); try { // 验证JWT并解析角色 Claims claims = jwtService.extractAllClaims(token); List<String> userRoles = claims.get("roles", List.class); // 检查用户是否拥有至少一个所需角色 boolean hasRequiredRole = userRoles.stream().anyMatch(requiredRoles::contains); if (!hasRequiredRole) { httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足"); return; } // 验证通过,继续执行后续过滤器 chain.doFilter(request, response); } catch (JwtException e) { httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效的JWT令牌"); } } }
方法二:使用多SecurityFilterChain配置
Spring Boot 3支持多个SecurityFilterChain Bean,每个链通过securityMatcher匹配特定路径,独立配置对应的过滤器和授权规则。
@RequiredArgsConstructor @Configuration @EnableWebSecurity public class SecurityConfig { private final JwtService jwtService; // 用户路径的SecurityFilterChain,优先级最高 @Bean @Order(1) public SecurityFilterChain userSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/api/users/**") .csrf(csrf -> csrf.disable()) .cors(cors -> cors.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(new AuthenticationFilter(jwtService, List.of("USER", "ADMIN")), BasicAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()); return http.build(); } // 管理员路径的SecurityFilterChain @Bean @Order(2) public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/api/admins/**") .csrf(csrf -> csrf.disable()) .cors(cors -> cors.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(new AuthenticationFilter(jwtService, List.of("ADMIN")), BasicAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()); return http.build(); } // 其他路径的默认配置,优先级最低 @Bean @Order(3) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .cors(cors -> cors.disable()) .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()); return http.build(); } }
两种方案均可解决问题:方法一适合过滤器逻辑独立且需要精准控制路径的场景;方法二更贴合Spring Security的链式配置风格,便于统一管理不同路径的安全规则。
内容的提问来源于stack exchange,提问作者Valentin Stamate
相关产品推荐
相关产品推荐

