最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Spring Security: APIKeyAuthenticationFilter not executing before JwtAuthFilter in API Gateway - Stack Overflow

programmeradmin2浏览0评论

I have a Spring Security setup where:

JwtAuthFilter is a common authentication filter used across all modules. APIKeyAuthenticationFilter should be executed only in the API Gateway module and must run before JwtAuthFilter.

However, in my API Gateway module, JwtAuthFilter always executes first, and APIKeyAuthenticationFilter is never applied. I need APIKeyAuthenticationFilter to execute first in the API Gateway, and then JwtAuthFilter.

Security Configuration for API Gateway:

@Configuration
@EnableWebSecurity
@Order(-1) 
public class APIGatewaySecurityConfiguration {

    @Autowired
    APIKeyAuthenticationFilter authFilter;

    @Bean
    @Order(1)  // Ensure ordering in security filter chain
    public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationEntryPoint authenticationEntryPoint) throws Exception {
        http.csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/pzp/**").authenticated()
                .anyRequest().authenticated()
            )
            .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class) // API Key filter should execute first
            .exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPoint));
        
        return http.build();
    }
}

APIKeyAuthenticationFilter:

@Component
@Order(-1)  
public class APIKeyAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    APIKeyAuthenticationProvider provider;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String apiKey = request.getHeader("apiKey");
        if (apiKey == null || apiKey.isEmpty()) {
            filterChain.doFilter(request, response);
            return;
        }

        try {
            Authentication authRequest = new APIKeyAuthenticationToken(apiKey);
            Authentication authResult = provider.authenticate(authRequest);
            SecurityContextHolder.getContext().setAuthentication(authResult);
        } catch (AuthenticationException e) {
            SecurityContextHolder.clearContext();
        }

        filterChain.doFilter(request, response);
    }
}

Security Configuration for JwtAuthFilter:

@Configuration
@EnableWebSecurity
@Order(99) // Should run after API Gateway security configuration
public class OAuth2SecurityConfiguration {

    private final Logger logger = LoggerFactory.getLogger(OAuth2SecurityConfiguration.class);

    @Autowired
    RemoteTokenServices wSO2TokenServices;

    @Autowired
    OAuth2AuthenticationManager oAuth2AuthenticationManager;

    @Autowired
    AuthProperties authProperties;

    @Autowired
    JwtAuthFilter jwtAuthFilter;

    @Autowired
    CommonAbstractLogFilter commonAbstractLogFilter;

    @PostConstruct
    public void done() {
        logger.info("Initialization completed for OAuth2SecurityConfiguration");
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    @Order(10) // Should execute after APIKeyAuthenticationFilter in API Gateway
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(getAntPathRequestMatchers()).anonymous()
                        .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.OPTIONS.toString())).permitAll()
                        .requestMatchers(new AntPathRequestMatcher("/pzp/**")).permitAll()
                        .anyRequest().authenticated()
                )
                .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .headers(headers -> headers.addHeaderWriter((request, response) -> {
                    response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
                    response.addHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
                }))
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) // Should execute after APIKeyAuthenticationFilter
                .addFilterAfter(commonAbstractLogFilter, JwtAuthFilter.class)
                .build();
    }

    private AntPathRequestMatcher[] getAntPathRequestMatchers() {
        String[] urls = authProperties.getAnonymousURLs();
        AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[urls.length + 1];
        for (int i = 0; i < urls.length; i++) {
            requestMatchers[i] = new AntPathRequestMatcher(urls[i]);
        }
        requestMatchers[urls.length] = new AntPathRequestMatcher("/api/v1/login");
        return requestMatchers;
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() throws Exception {
        String[] urls = authProperties.getAnonymousURLs();

        logger.info("Ignored list of resources {} ", authProperties.getAnonymousURLs());

        Set<AntPathRequestMatcher> matchers = new HashSet<>();
        for (String url : urls) {
            matchers.add(new AntPathRequestMatcher(url));
        }

        return web -> web.ignoring().requestMatchers(matchers.toArray(new AntPathRequestMatcher[0]))
                .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.OPTIONS.toString()));
    }
}

JwtAuthFilter (Global Authentication Filter for All Modules):

@Component
@Order(10) // Should execute after APIKeyAuthenticationFilter in API Gateway
public class JwtAuthFilter extends OncePerRequestFilter {
    
    @Autowired
    private JwtService jwtService;

    @Autowired
    AccessTokenConverter accessTokenConverter; 
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        try {
            String token = authHeader.substring(7);
            Jwt jwt = jwtService.extractJwt(token);
            AbstractAuthenticationToken authentication = accessTokenConverter.convert(jwt);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        filterChain.doFilter(request, response);
    }
}

Issue: In the API Gateway, JwtAuthFilter is executed before APIKeyAuthenticationFilter, but I need APIKeyAuthenticationFilter to run first. I have already tried setting @Order(-1) for APIKeyAuthenticationFilter and adding it before UsernamePasswordAuthenticationFilter, but it is still skipped.

**Question: How do I ensure that:

APIKeyAuthenticationFilter executes first in API Gateway. JwtAuthFilter executes after APIKeyAuthenticationFilter only in API Gateway. JwtAuthFilter remains the first filter in all other modules. Would appreciate any insights on ordering filters correctly in Spring Boot 3.**

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论