You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,也会导致过滤器无法正常实例化。

具体修复步骤

  1. 禁用默认认证入口
    在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();
    }
    
  2. 添加RestTemplate Bean定义
    自定义过滤器依赖RestTemplate,需在配置类中定义该Bean:

    @Configuration
    public class RestTemplateConfig {
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
  3. 完善令牌验证逻辑
    补充调用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
    );
    
  4. 处理认证失败场景
    当AuthService返回无效令牌或请求失败时,直接返回401状态码,终止过滤器链:

    if (!authResponse.getStatusCode().is2xxSuccessful() || authResponse.getBody() == null) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return;
    }
    
  5. 确保权限集合格式正确
    确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:17:34