By removing @Component, the filter will not be picked up automatically by the servlet container.
@Slf4j
//@Component -> Remove this
@RequiredArgsConstructor
public class JwtAuthenticationFilter implements WebFilter {
private final JwtTokenProvider jwtTokenProvider;
@NonNull
@Override
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
log.debug("Processing request: {} {} at {}", exchange.getRequest().getMethod(), exchange.getRequest().getPath(), System.currentTimeMillis());
String token = resolveToken(exchange.getRequest());
if (StringUtils.hasText(token) && this.jwtTokenProvider.isTokenValid(token)) {
return chain.filter(exchange).contextWrite(ReactiveSecurityContextHolder.withAuthentication(this.getAuthentication(token)));
}
return chain.filter(exchange);
}
private String resolveToken(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
This avoids multiple registrations in the Spring context and ensures that the filter is only applied within the Spring Security filter chain.
@Configuration
@EnableWebFluxSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
JwtAuthenticationFilter jwtFilter = new JwtAuthenticationFilter(jwtTokenProvider); // add it here
return http
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.cors(ServerHttpSecurity.CorsSpec::disable)
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
.formLogin(ServerHttpSecurity.FormLoginSpec::disable)
.logout(ServerHttpSecurity.LogoutSpec::disable)
.authorizeExchange(exchanges -> exchanges
.pathMatchers(WHITE_LIST_URL).permitAll()
.anyExchange().authenticated()
)
.addFilterAt(jwtFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.build();
}
}