
Qué es la cadena de filtros de Spring Security
Spring Security se integra en el stack servlet como un único filtro, FilterChainProxy, que actúa como punto de entrada. Dentro de ese filtro, Spring Security ejecuta una cadena ordenada de filtros especializados, cada uno con una responsabilidad concreta: cargar el contexto de seguridad, autenticar, autorizar, proteger frente a CSRF o generar cabeceras seguras.
La abstracción que representa esa cadena es SecurityFilterChain. Desde Spring Security 6 y Spring Boot 3 la configuración se expresa declarando un bean de este tipo, en lugar de extender la antigua clase WebSecurityConfigurerAdapter.
Bean SecurityFilterChain
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated())
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
}
Cada bean SecurityFilterChain se aplica solo a las peticiones que coinciden con su securityMatcher. Puedes definir varias cadenas independientes para separar, por ejemplo, una API REST sin sesión y una aplicación MVC con formulario de login.
Orden de los filtros
Los filtros se ejecutan siempre en el mismo orden. Los más relevantes son:
DisableEncodeUrlFilter: desactiva la reescritura de URL con jsessionid.SecurityContextHolderFilter: carga elSecurityContextasociado a la sesión.HeaderWriterFilter: escribe cabeceras de seguridad en la respuesta.CsrfFilter: valida el token CSRF en peticiones que lo requieren.LogoutFilter,UsernamePasswordAuthenticationFilter,BearerTokenAuthenticationFilter,BasicAuthenticationFilter: se ocupan de la autenticación según el mecanismo elegido.ExceptionTranslationFilter: traduce excepciones de seguridad en respuestas HTTP coherentes.AuthorizationFilter: evalúa las reglas de acceso definidas enauthorizeHttpRequests.
Filtros personalizados
Puedes insertar filtros propios antes o después de los filtros estándar usando http.addFilterBefore o http.addFilterAfter. Es el mecanismo clásico para integrar JWT, auditoría de accesos o controles de rate limiting.
http.addFilterBefore(new JwtAuthenticationFilter(authManager),
UsernamePasswordAuthenticationFilter.class);
Entender este orden es clave para depurar errores de autenticación: un filtro que falla en mitad de la cadena impide que el controlador llegue a ejecutarse.
Múltiples SecurityFilterChain en la misma aplicación
Una aplicación corporativa típica expone al menos dos superficies HTTP con requisitos de seguridad distintos: una API REST stateless protegida con JWT para clientes SPA y móviles, y una zona web con formulario de login y sesión HTTP para usuarios internos. En Spring Security ambas conviven como SecurityFilterChain independientes, con un securityMatcher y una prioridad declarada mediante @Order.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
@Order(1)
SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated())
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.build();
}
@Bean
@Order(2)
SecurityFilterChain webFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login", "/css/**").permitAll()
.anyRequest().authenticated())
.formLogin(form -> form.loginPage("/login"))
.logout(Customizer.withDefaults())
.build();
}
}
La cadena con menor @Order se evalúa primero. Si el securityMatcher no encaja, Spring Security pasa a la siguiente cadena. Esta separación permite mantener CSRF activo en la zona web y desactivado en la API REST sin colisiones.
Debugging del orden de filtros
Para depurar el contenido real de cada cadena se activa el log de Spring Security en DEBUG o se expone el endpoint de Actuator mappings. Un fallo frecuente en proyectos corporativos es colocar un filtro JWT personalizado después del AuthorizationFilter: el usuario nunca llega autenticado al momento de evaluar las reglas y todas las peticiones devuelven 403. La solución es siempre insertarlo antes de UsernamePasswordAuthenticationFilter con addFilterBefore.
Casos de uso B2B
- Banca y fintech: tres cadenas separadas para APIs públicas, back office y canal móvil, cada una con su propio filtro JWT, reglas de CORS y política de sesión.
- Sector público: integración de filtro SAML 2.0 o Cl@ve como
AuthenticationFilterpropio antes delUsernamePasswordAuthenticationFilter. - Telco y ecommerce: un filtro de rate limiting (Bucket4j, Resilience4j) insertado al principio de la cadena para proteger endpoints de login y checkout frente a abuso.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Spring Boot es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Spring Boot
Explora más contenido relacionado con Spring Boot y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Comprender la arquitectura de Spring Security y el patrón de cadena de filtros. Identificar los filtros principales y su orden de ejecución. Configurar varias SecurityFilterChain coexistiendo en una misma aplicación.