Spring Boot Security自定义过滤器未触发问题排查求助
基于Spring Boot 3.2.0和Java 17开发微服务架构,AuthService负责认证逻辑:用户登录后获取JWT令牌,携带该令牌以Bearer格式放入请求头,即可访问EmployeeService等其他业务服务。设计思路是让EmployeeService通过自定义过滤器调用AuthService的/auth/validate接口完成令牌验证与用户信息获取,不在本地处理认证逻辑。
当前遇到的问题:即使请求头携带了合法的Authorization令牌,EmployeeService仍会将请求重定向到Spring默认登录页,且自定义的AppSecurityFilter从未被触发。
相关代码如下:
ApplicationSecurity 配置类
@RefreshScope @Configuration @EnableWebSecurity @RequiredArgsConstructor public class ApplicationSecurity { private final AppSecurityFilter appSecurityFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(appSecurityFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth .requestMatchers("/health") .permitAll() .anyRequest() .authenticated()) .build(); } }
AppSecurityFilter 自定义过滤器
@AllArgsConstructor @Component public class AppSecurityFilter extends OncePerRequestFilter { private static String AUTH_SERVER_VALIDATE_TOKEN_URL = "http://AUTH-SERVICE/auth/api/v1/validate"; private RestTemplate restTemplate; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { final String header = request.getHeader(AUTHORIZATION); if (isEmpty(header) || !header.startsWith("Bearer ")) { filterChain.doFilter(request, response); return; } ResponseEntity<AuthResponseDto> authResponse = // 通过restTemplate调用authService获取userDetails UserResponseDto user = authResponse.getBody().getUserResponseDto(); SecurityContextHolder.getContext().setAuthentication( new UsernamePasswordAuthenticationToken( user, null, user.getAuthorities() ) ); filterChain.doFilter(request, response); } }
核心原因
Spring Security在无状态会话模式下,默认会启用表单登录和HTTP Basic认证机制。当请求未通过认证时,会自动触发重定向到登录页的逻辑,而你的配置中未禁用这些默认机制,导致自定义过滤器还未执行就被拦截。此外,过滤器依赖的RestTemplate未定义Bean,也会导致过滤器无法正常实例化。
具体修复步骤
禁用默认认证入口
在SecurityFilterChain配置中显式禁用表单登录和HTTP Basic认证,避免自动重定向:@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 禁用默认表单登录和HTTP Basic,避免重定向 .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .addFilterBefore(appSecurityFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth .requestMatchers("/health") .permitAll() .anyRequest() .authenticated()) .build(); }添加RestTemplate Bean定义
自定义过滤器依赖RestTemplate,需在配置类中定义该Bean:@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }完善令牌验证逻辑
补充调用AuthService的代码,正确提取并传递令牌:// 提取Bearer令牌(去掉"Bearer "前缀) final String token = header.substring(7); // 构造请求头,将原Authorization令牌传递给AuthService HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set(HttpHeaders.AUTHORIZATION, header); HttpEntity<Void> requestEntity = new HttpEntity<>(requestHeaders); // 调用AuthService验证接口 ResponseEntity<AuthResponseDto> authResponse = restTemplate.exchange( AUTH_SERVER_VALIDATE_TOKEN_URL, HttpMethod.GET, requestEntity, AuthResponseDto.class );处理认证失败场景
当AuthService返回无效令牌或请求失败时,直接返回401状态码,终止过滤器链:if (!authResponse.getStatusCode().is2xxSuccessful() || authResponse.getBody() == null) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; }确保权限集合格式正确
确保user.getAuthorities()返回GrantedAuthority类型的集合,否则Spring Security无法识别权限:// 示例:如果UserResponseDto中的权限是字符串列表,需转换为GrantedAuthority List<GrantedAuthority> authorities = user.getRoles().stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); SecurityContextHolder.getContext().setAuthentication( new UsernamePasswordAuthenticationToken( user, null, authorities ) );
额外建议
- 微服务场景下,推荐使用Spring Cloud Gateway + OAuth2 Resource Server架构统一处理令牌验证,避免每个服务重复编写过滤器逻辑,提升安全性与可维护性。
- 为AuthService的验证接口添加超时、重试机制,避免因AuthService不可用导致业务服务瘫痪。
内容的提问来源于stack exchange,提问作者Erfan Ahmed

