Seguridad con Spring Security
La mayoría de las aplicaciones necesitan seguridad.
Por ejemplo:
- usuarios que deben iniciar sesión
- rutas protegidas
- permisos por roles
- autenticación con tokens
Spring Boot utiliza Spring Security para gestionar todo esto.
Spring Security es uno de los sistemas de seguridad más usados en aplicaciones Java.
1. Qué es autenticación y autorización #
Son dos conceptos diferentes.
Autenticación #
Responde a la pregunta:
¿Quién eres?
Ejemplo:
1usuario + contraseña
Autorización #
Responde a la pregunta:
¿Qué puedes hacer?
Ejemplo:
1admin → puede eliminar usuarios 2user → solo puede ver datos
2. Añadir Spring Security #
En pom.xml añadimos:
1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-security</artifactId> 4</dependency>
3. Qué ocurre al instalar Spring Security #
Cuando arrancas la aplicación:
Spring Boot protege todas las rutas automáticamente.
Si intentas acceder a:
1http://localhost:8080/users
verás una página de login.
Spring Security crea un usuario temporal.
En consola aparecerá algo como:
1Using generated security password: a1b2c3d4
4. Configuración básica de seguridad #
Podemos crear una clase de configuración.
5. Ejemplo #
1@Configuration 2@EnableWebSecurity 3public class SecurityConfig { 4 5}
6. Permitir acceso a algunas rutas #
Ejemplo: permitir acceso público a /hello.
1@Configuration 2@EnableWebSecurity 3public class SecurityConfig { 4 5 @Bean 6 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 7 8 http 9 .csrf().disable() 10 .authorizeHttpRequests(auth -> auth 11 .requestMatchers("/hello").permitAll() 12 .anyRequest().authenticated() 13 ) 14 .httpBasic(); 15 16 return http.build(); 17 } 18 19}
7. Explicación #
| código | función |
|---|---|
| csrf().disable() | desactiva protección CSRF |
| permitAll() | acceso público |
| authenticated() | requiere login |
| httpBasic() | autenticación básica |
8. Crear usuarios en memoria #
Podemos crear usuarios manualmente.
9. Ejemplo #
1@Bean 2public UserDetailsService users() { 3 4 UserDetails user = User 5 .withUsername("user") 6 .password("{noop}1234") 7 .roles("USER") 8 .build(); 9 10 UserDetails admin = User 11 .withUsername("admin") 12 .password("{noop}admin") 13 .roles("ADMIN") 14 .build(); 15 16 return new InMemoryUserDetailsManager(user, admin); 17 18}
10. Explicación #
1user → rol USER 2admin → rol ADMIN
11. Proteger rutas por roles #
Podemos restringir rutas.
12. Ejemplo #
1.authorizeHttpRequests(auth -> auth 2 .requestMatchers("/admin/**").hasRole("ADMIN") 3 .requestMatchers("/users/**").hasRole("USER") 4 .anyRequest().authenticated() 5)
13. Resultado #
1/admin → solo admin 2/users → user o admin
14. Usar JWT en APIs #
En APIs modernas normalmente no se usa login con sesión.
Se usa JWT (JSON Web Token).
Flujo típico:
1cliente → login 2servidor → genera token JWT 3cliente → envía token en cada petición
15. Ejemplo token #
1Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI...
16. Flujo de autenticación JWT #
11 login 22 servidor valida usuario 33 genera token 44 cliente guarda token 55 cliente envía token en cada petición
17. Ejemplo endpoint login #
1@PostMapping("/login") 2public String login(@RequestBody LoginRequest request) { 3 4 if(request.getUsername().equals("admin") 5 && request.getPassword().equals("1234")) { 6 7 return jwtService.generateToken(request.getUsername()); 8 9 } 10 11 throw new RuntimeException("Credenciales inválidas"); 12}
18. Verificar token #
Cada petición incluirá:
1Authorization: Bearer TOKEN
Spring Security intercepta la petición y valida el token.
19. Ventajas de JWT #
| ventaja | explicación |
|---|---|
| stateless | no guarda sesión |
| escalable | ideal para microservicios |
| rápido | verificación simple |
| portable | funciona en cualquier cliente |
20. Buenas prácticas de seguridad #
Nunca guardar contraseñas en texto plano #
Usar hash.
Ejemplo:
1BCrypt
Usar HTTPS #
Evita robo de credenciales.
Limitar permisos #
No dar acceso admin a todos.
Validar siempre tokens #
Nunca confiar en el cliente.
21. Ejemplo simple completo #
1@Configuration 2@EnableWebSecurity 3public class SecurityConfig { 4 5 @Bean 6 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 7 8 http 9 .csrf().disable() 10 .authorizeHttpRequests(auth -> auth 11 .requestMatchers("/public/**").permitAll() 12 .requestMatchers("/admin/**").hasRole("ADMIN") 13 .anyRequest().authenticated() 14 ) 15 .httpBasic(); 16 17 return http.build(); 18 } 19 20}
Resumen del tema
Conceptos clave #
- Autenticación vs Autorización: autenticación verifica la identidad del usuario (¿quién eres?) y autorización evalúa sus permisos y roles (¿qué puedes hacer?).
- Cadena de Filtros (
SecurityFilterChain): configuración moderna basada en beans conhttp.authorizeHttpRequests(), declarando rutas públicas conpermitAll()y protegidas conhasRole()/hasAuthority(). - Estrategia sin Estado (Stateless) con JWT: desactivación de CSRF y sesiones HTTP en favor de tokens JWT transmitidos en la cabecera
Authorization: Bearer <token>. - Codificación Segura de Contraseñas: uso obligatorio de
PasswordEncoder(específicamenteBCryptPasswordEncoder) para evitar almacenar texto plano. - Seguridad a Nivel de Método: activación con
@EnableMethodSecurityy uso de@PreAuthorize("hasRole('ADMIN')").
Qué debes recordar #
Configura una cadena SecurityFilterChain declarativa sin estado con JWT y BCryptPasswordEncoder para asegurar APIs REST protegiendo endpoints por roles y permisos.