Cualquier aplicación, ya sea una tienda online gigante o un servicio de notas pequeño, tiene ciertos recursos que necesitan protección: pueden ser datos de usuarios, información confidencial u operaciones que cambian el estado del sistema. Y nuestra tarea como desarrolladores es hacer que esos recursos estén disponibles solo para quienes tienen derecho a acceder.
Sin un nivel de protección adecuado, cualquiera con software básico (sí, estamos mirando hacia Postman) podrá acceder a la API, y eso es algo que no queremos permitir.
OAuth2 ofrece una herramienta excelente para gestionar el acceso: los tokens. Hoy veremos cómo configurar tu proyecto Spring Boot para asegurar estrictamente los recursos.
Componentes para proteger recursos
Antes de meternos en la práctica, definamos brevemente los componentes clave que necesitaremos para proteger recursos con OAuth2:
- Servidor de recursos (Resource Server):
- El componente que sirve los datos protegidos y verifica los tokens antes de conceder acceso. Aquí es donde normalmente desplegarías tus REST API.
- Token de acceso (Access Token):
- Un token especial con el que el cliente puede llamar al servidor de recursos. El token contiene información, por ejemplo, qué acciones están permitidas y para qué usuario.
- Roles y permisos de acceso:
- Gestión del acceso mediante roles (por ejemplo,
ROLE_USER,ROLE_ADMIN) y scopes, que definen las capacidades funcionales del usuario.
- Gestión del acceso mediante roles (por ejemplo,
- Spring Security:
- El framework que te permite organizar la verificación de permisos a recursos, la validación de tokens y la configuración de políticas de seguridad.
Implementación de la protección de recursos en Spring Boot
Pongámonos prácticos. Vamos a configurar una aplicación Spring Boot en el rol de servidor de recursos, usando OAuth2 y JWT.
Preparación del proyecto
Asegúrate de tener el siguiente conjunto de dependencias en tu pom.xml (o build.gradle):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Estas dependencias añaden soporte para el servidor de recursos y Spring Security.
Configuración del servidor de recursos
1. Configuración de los filtros de security
Crea una clase de configuración para Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // Recursos públicos
.antMatchers("/admin/**").hasRole("ADMIN") // Solo para administradores
.antMatchers("/user/**").hasRole("USER") // Solo para usuarios
.anyRequest().authenticated() // Todas las demás requieren autenticación
.and()
.oauth2ResourceServer()
.jwt(); // Usamos JWT para validar el token
}
}
Aquí definimos:
- Qué endpoints son públicos.
- Qué recursos requieren roles específicos.
- Configuramos el OAuth2 resource server usando JWT.
2. Configuración de tokens JWT
Añade en application.yml (o application.properties) los parámetros para indicar dónde buscar la clave pública para verificar la firma de los tokens JWT:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth-server.example.com/realms/myrealm
# Aquí debe ir la URL de tu servidor de autorización (Issuer URI)
El parámetro issuer-uri le dice a Spring Security dónde está el servidor de autorización (por ejemplo, Keycloak o Auth0) para obtener la información de configuración de los tokens.
Ejemplo de un controlador protegido
Creemos un REST controller que muestra el uso de roles y scopes.
@RestController
@RequestMapping("/api")
public class ResourceController {
@GetMapping("/public")
public String publicEndpoint() {
return "¡Este es un recurso público, accesible para todos!";
}
@GetMapping("/user/hello")
public String userEndpoint(@AuthenticationPrincipal Jwt jwt) {
return "¡Hola, usuario " + jwt.getClaimAsString("preferred_username") + "!";
}
@GetMapping("/admin/dashboard")
public String adminEndpoint() {
return "Este es un recurso administrativo. ¡Bienvenido, gran administrador!";
}
}
- El endpoint
/publicestá disponible para todos. - El endpoint
/user/hellorequiere el roleUSERy muestra información desde el token JWT (por ejemplo,preferred_username). - El endpoint
/admin/dashboardestá disponible solo para administradores.
¿Cómo comprobar que el servidor funciona?
- Paso 1: obtén un token JWT. Hazlo a través del servidor de autorización (por ejemplo, Keycloak o Auth0).
- Paso 2: envía la petición con el header
Authorization: Bearer <tu token>a los endpoints protegidos. - Paso 3: asegúrate de que el acceso se concede o se rechaza según el role y el scope.
Gestión de roles y permisos
Los roles en OAuth2 y JWT juegan un papel clave para dar acceso a recursos. Por ejemplo, el rol ROLE_ADMIN permite acceso a recursos administrativos, y ROLE_USER a recursos de usuario.
El token JWT puede incluir scopes y roles como claims adicionales. Ejemplo de la estructura de un token:
{
"sub": "user123",
"scope": "read write",
"roles": ["USER", "ADMIN"],
"exp": 1698777600
}
¿Cómo comprobar roles en Spring? Spring Security convierte automáticamente los roles del token en autoridad. Puedes usar anotaciones:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/secure/admin")
public String securedAdminEndpoint() {
return "¡Solo para administradores!";
}
Errores típicos y cómo solucionarlos
- Error "403 Forbidden" al acceder con un token válido — probablemente tengas mal configurados los roles o los scopes. Asegúrate de que los roles incluidos en el token coinciden con los esperados.
- Error de verificación de la firma JWT — normalmente significa que tu resource server no pudo obtener la clave pública del servidor de autorización. Revisa el parámetro
issuer-uriy verifica que el servidor de autorización esté accesible. - Token caducado — asegúrate de que tus clientes usan Refresh tokens para renovar los access tokens.
Aplicación en la vida real
Usar OAuth2 y JWT para proteger recursos ofrece una seguridad fiable y escalable para arquitecturas de microservicios. Este enfoque se usa en muchos proyectos reales, desde aplicaciones corporativas hasta plataformas de autenticación social.
La próxima vez que entres a un sitio y veas el botón "Entrar con Google", ya sabrás que ahí está funcionando OAuth2.
GO TO FULL VERSION