Hoy pasamos a la práctica — vamos a crear una aplicación web básica con Spring Security para proteger rutas y manejar la autenticación de usuarios. ¡Preparados para la acción, amigos!
De construir la aplicación a añadir seguridad
Objetivo y estructura de la tarea
Antes de escribir código, imaginemos que no solo hacemos una app, sino un restaurante digital. Necesitamos saber quién viene de visita (autenticación) y a qué zonas puede acceder (autorización). En un restaurante real hay control de acceso y zonas VIP; en nuestra app tendremos Spring Security.
Este es nuestro plan:
- Crearemos una aplicación mínima de Spring Boot — nuestro "restaurante"
- Añadiremos protección básica con Spring Security — pondremos "puertas y cerraduras"
- Configuraremos el sistema de verificación de visitantes — ¿quién eres y se te puede confiar?
- Definiremos reglas de acceso a distintas zonas — quién puede ir a cada sitio
- Probaremos nuestra seguridad vía navegador o Postman — haremos una visita de prueba
¿Listos para montar el restaurante digital más seguro? ¡Vamos a ello!
Paso 1: Creamos una aplicación Spring Boot minimalista
Primero creamos un nuevo proyecto Spring Boot. Selecciona las dependencias:
- Spring Web — para que nuestra app pueda manejar peticiones HTTP.
- Spring Security — para configurar la seguridad.
No olvides añadir Gradle o Maven en tu proyecto. Por ejemplo, para Maven tu pom.xml se verá así:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
Ahora añadamos un controlador sencillo.
@RestController
public class GreetingController {
@GetMapping("/public")
public String publicEndpoint() {
return "¡Este endpoint está disponible para todos!";
}
@GetMapping("/secure")
public String secureEndpoint() {
return "¡Has entrado en la zona protegida!";
}
}
Arranca la aplicación y prueba abrir las rutas /public y /secure. Fíjate en que Spring Security ya protege todo tu API. Intenta acceder a /secure y verás la pantalla de login del navegador. Esta es la protección básica que Spring Security ofrece "out of the box".
Paso 2: Configuración básica
Ahora crearemos una configuración de seguridad personalizada. Tenemos que asegurarnos de que:
/publicsiga abierto para todos./secureesté protegido y accesible solo para usuarios autenticados.
Creamos la clase de configuración.
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public").permitAll() // Acceso abierto para todos
.anyRequest().authenticated() // Todas las demás peticiones requieren autenticación
.and()
.formLogin() // Activamos el formulario de login estándar
.and()
.httpBasic(); // Activamos la autorización HTTP Basic
}
}
Arranca la app de nuevo. Ahora /public se abre sin problemas, y el acceso a /secure exige introducir usuario y contraseña mediante el formulario de login estándar.
Paso 3: Configurar usuarios
Por defecto Spring Security usa un usuario predefinido llamado user y una contraseña aleatoria, que aparece en los logs al arrancar la app. Si estás cansado de buscar la contraseña en los logs, añadamos nuestros propios usuarios en application.properties.
spring.security.user.name=admin
spring.security.user.password=admin123
Ahora el usuario admin podrá autenticarse con la contraseña admin123.
Pero si necesitamos añadir diferentes roles (por ejemplo, administradores y usuarios normales), ajustemos un poco el sistema.
Paso 4: Añadir autorización basada en roles
Añadiremos dos roles: ROLE_ADMIN y ROLE_USER. Primero actualizamos la configuración de seguridad:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public").permitAll()
.antMatchers("/secure").hasRole("ADMIN") // Acceso a /secure solo para administradores
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
Ahora creemos usuarios con diferentes roles. Para ello sobreescribimos el método configure en nuestra clase SecurityConfig:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin123")).roles("ADMIN") // Administrador
.and()
.withUser("user").password(passwordEncoder().encode("user123")).roles("USER"); // Usuario normal
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Ahora tenemos dos usuarios:
admincon contraseñaadmin123y rolROLE_ADMIN.usercon contraseñauser123y rolROLE_USER.
Y solo el administrador (admin) podrá acceder a /secure.
Paso 5: Probamos la seguridad
Arranca la aplicación y pruébala:
- Abre
/public— acceso abierto para todos. - Abre
/secure— el sistema pedirá login y contraseña.- Introduce
user/user123— recibirás un rechazo de acceso. - Introduce
admin/admin123— obtendrás acceso.
- Introduce
También puedes testear con Postman. Por ejemplo, una petición a /secure la puedes enviar usando Basic Auth y poniendo usuario y contraseña.
Paso 6: Revisamos el archivo application.properties
Esto es útil añadir en application.properties para mayor facilidad:
# Registro para depuración
logging.level.org.springframework.security=DEBUG
Así podrás ver más información sobre cómo Spring Security procesa tus peticiones.
Errores comunes
- Error: el acceso a rutas protegidas se concede a cualquier usuario. Suele ocurrir por reglas mal configuradas en
authorizeRequests. Revisa el orden de las llamadas aantMatchers— se procesan de arriba abajo. IllegalArgumentException: There is no PasswordEncoder mapped for ID "null". Esto pasa si olvidas configurar unPasswordEncoder. No te olvides de añadir el beanBCryptPasswordEncoderen tu código para encriptar las contraseñas.
El siguiente paso será persistir usuarios y roles en una base de datos, que veremos en próximas lecciones. ¿Quién no necesita integrar con una base real, verdad?
GO TO FULL VERSION