
AuthenticationManager como punto de entrada
AuthenticationManager es la interfaz que los filtros de autenticación invocan al recibir credenciales. Su única responsabilidad es tomar un objeto Authentication sin autenticar y devolver una versión autenticada o lanzar AuthenticationException.
La implementación por defecto es ProviderManager, que mantiene una lista ordenada de AuthenticationProvider. Cada provider declara si soporta un tipo concreto de Authentication (usuario/password, token JWT, etcetera) y, si lo soporta, intenta autenticarlo.
Cadena de providers
Si el primer provider devuelve null, ProviderManager pregunta al siguiente. Si ninguno soporta el tipo de Authentication recibido, se lanza ProviderNotFoundException.
DaoAuthenticationProvider
Para autenticación clásica usuario/contraseña se utiliza DaoAuthenticationProvider, que combina un UserDetailsService con un PasswordEncoder.
@Bean
DaoAuthenticationProvider daoAuthenticationProvider(UserDetailsService uds,
PasswordEncoder encoder) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(uds);
provider.setPasswordEncoder(encoder);
return provider;
}
@Bean
AuthenticationManager authenticationManager(List<AuthenticationProvider> providers) {
return new ProviderManager(providers);
}
Al registrar el bean AuthenticationManager, Spring Security lo inyecta en los filtros por defecto, de modo que el flujo de login por formulario queda conectado automáticamente.
Combinar varios providers
Cuando una aplicación expone login MVC y API REST con JWT, es habitual configurar dos providers coexistiendo:
DaoAuthenticationProviderpara el flujo MVC, sobre una base de datos de usuarios.JwtAuthenticationProvideroJwtAuthenticationConverterpara la API REST sin estado.
ProviderManager selecciona el adecuado en función del tipo concreto de Authentication (por ejemplo, UsernamePasswordAuthenticationToken frente a BearerTokenAuthenticationToken). Esa separación hace posible mantener ambas superficies sin duplicar lógica de seguridad.
Cache y borrado de credenciales
ProviderManager borra por defecto las credenciales después de autenticar para evitar que queden expuestas en memoria. Si necesitas reusarlas, puedes desactivar el comportamiento con setEraseCredentialsAfterAuthentication(false), asumiendo el riesgo correspondiente.
Flujo completo con DaoAuthenticationProvider
El caso más habitual en aplicaciones corporativas es autenticar contra una base de datos de usuarios. El flujo combina UserDetailsService, PasswordEncoder y DaoAuthenticationProvider dentro de un ProviderManager.
Si UserDetailsService devuelve null, DaoAuthenticationProvider ejecuta igualmente un hash ficticio para evitar time attacks que permitan deducir usuarios existentes midiendo el tiempo de respuesta.
AuthenticationProvider personalizado
Cuando los usuarios viven en un sistema externo (LDAP corporativo, API HR, broker SSO interno) se implementa un provider propio. La interfaz solo exige dos métodos:
@Component
public class LdapAuthenticationProvider implements AuthenticationProvider {
private final LdapClient ldap;
public LdapAuthenticationProvider(LdapClient ldap) {
this.ldap = ldap;
}
@Override
public Authentication authenticate(Authentication authentication) {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
LdapUser user = ldap.bindAndSearch(username, password);
if (user == null) {
throw new BadCredentialsException("Credenciales invalidas");
}
List<SimpleGrantedAuthority> authorities = user.getGroups().stream()
.map(g -> new SimpleGrantedAuthority("ROLE_" + g))
.toList();
return new UsernamePasswordAuthenticationToken(username, null, authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
El bean queda detectado automáticamente por Spring y ProviderManager lo añade a la lista de providers disponibles.
Casos de uso B2B
- Banca: un provider contra el directorio corporativo para empleados de oficina y otro contra la base de datos de clientes para banca electrónica, coexistiendo en el mismo backend.
- Sector público: provider para Cl@ve o certificado digital eIDAS combinado con DaoAuthenticationProvider para usuarios administrativos internos.
- Fintech y ecommerce: provider JWT para APIs públicas, OAuth2 para integraciones con proveedores externos (Google, Apple, Microsoft) y DaoAuthenticationProvider para back office.
Depuración habitual
Si AuthenticationException llega al cliente sin un mensaje útil:
- Activa logs en
org.springframework.security.authenticationa nivelDEBUGpara ver la cadena de providers consultados. - Comprueba que el bean
AuthenticationManageresta declarado y se inyecta en los filtros (desde Spring Security 6, el bean no se crea por defecto en todas las configuraciones). - Si los hashes BCrypt tienen formato antiguo (
$2a$vs$2b$), usaDelegatingPasswordEncoderpara reconocer variantes y migrarlas en el siguiente login.
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 el rol de AuthenticationManager y ProviderManager. Configurar DaoAuthenticationProvider con UserDetailsService. Combinar varios providers para distintos flujos de autenticación.