Fundamentos de Spring Security (Spring Framework)
Spring Security es el módulo encargado de proteger aplicaciones Spring, ya sea MVC clásico o servicios REST. Aunque Spring Boot facilita su configuración, puedes usarlo en proyectos Spring “a secas” con total control.
Componentes clave
- SecurityContext: almacena la autenticación actual (usuario y roles).
- AuthenticationManager: procesa autenticaciones.
- UserDetailsService y PasswordEncoder: resuelven credenciales.
- Filter Chain: filtros que interceptan cada petición HTTP (autenticación, autorización, CSRF, headers…).
Configuración básica (Java)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**", "/login").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(login -> login
.loginPage("/login")
.defaultSuccessUrl("/dashboard", true))
.logout(logout -> logout.logoutSuccessUrl("/login?logout"))
.csrf(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder().encode("secret"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- En aplicaciones sin Boot register
DelegatingFilterProxyenweb.xmlapuntando aspringSecurityFilterChain.
Autenticación personalizada
- Implementa
UserDetailsServicepara cargar usuarios desde base de datos. - Usa
DaoAuthenticationProvidero crea unAuthenticationProviderpropio.
@Component
public class JpaUserDetailsService implements UserDetailsService {
private final UsersRepository repository;
public UserDetails loadUserByUsername(String username) {
return repository.findByUsername(username)
.map(user -> User.withUsername(user.username())
.password(user.passwordHash())
.roles(user.role())
.build())
.orElseThrow(() -> new UsernameNotFoundException(username));
}
}
API REST con JWT
@Configuration
@EnableWebSecurity
public class ApiSecurityConfig {
@Bean
SecurityFilterChain apiFilterChain(HttpSecurity http, JwtAuthFilter jwtFilter) throws Exception {
http
.securityMatcher("/api/**")
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated());
return http.build();
}
}
JwtAuthFilter valida el token, construye una UsernamePasswordAuthenticationToken y la almacena en el SecurityContext.
Autorización declarativa
- Usa
@EnableMethodSecurity(o@EnableGlobalMethodSecurityen versiones previas). - Anota métodos con
@PreAuthorize("hasRole('ADMIN')"),@PostAuthorize,@PreFilter, etc. - Integra
SecurityExpressionHandlerpara expresiones personalizadas.
@Service
public class PaymentsService {
@PreAuthorize("hasAuthority('PAYMENTS_APPROVE')")
public void approvePayment(UUID id) {}
}
CSRF, CORS y cabeceras
- CSRF está habilitado por defecto para formularios web; deshabilítalo sólo en APIs stateless.
- Configura CORS cuando el frontend está en dominio distinto:
http.cors(cors -> cors.configurationSource(request -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://frontend.antoniosaborido.es"));
config.setAllowedMethods(List.of("GET","POST","PATCH"));
config.setAllowedHeaders(List.of("Authorization","Content-Type"));
return config;
}));
- Spring Security gestiona cabeceras como HSTS, X-Content-Type-Options, XSS-Protection.
Protección de servicios gRPC / WebSocket
- Spring Security integra interceptores para WebSockets (
ChannelInterceptor) y mensajes STOMP. - Para gRPC puedes envolver el servidor en filtros de autenticación (
io.grpc.ServerInterceptors.intercept).
Testing de seguridad
@WithMockUserpara simular usuarios en testsMockMvc.SecurityMockMvcRequestPostProcessors.jwt()para JWT.TestSecurityContextHoldermanipula el contexto en pruebas unitarias.
@WebMvcTest(controllers = AdminController.class)
class AdminControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void permiteAccesoAdmin() throws Exception {
mockMvc.perform(get("/admin")).andExpect(status().isOk());
}
}
Integración con OAuth2 / OpenID Connect
- Usa
spring-security-oauth2-clientpara login social o SSO corporativo. - Configura
ClientRegistrationRepositoryyOAuth2AuthorizedClientService. - Para resource servers añade validación de token (
NimbusJwtDecoder, introspection).
Buenas prácticas
- Encripta contraseñas con BCrypt/Argon2; nunca almacenes texto plano.
- Agrupa permisos en roles y documenta su significado.
- Configura sesiones seguras (
sessionFixation().migrateSession(),maximumSessions(1)para apps sensibles). - Monitoriza intentos fallidos y bloquea IPs sospechosas con
ApplicationEventPublisher. - Externaliza secretos en un vault; evita hardcodear API keys.
Con esta base puedes proteger aplicaciones Spring Framework sin depender de Spring Boot, manteniendo el control sobre autenticación, autorización y políticas de seguridad avanzadas.