La anotación @EnableResourceServer se aplica a una clase de configuración @Configuration. La configuración se realiza mediante el objeto ResourceServerConfigurer. Una forma común es extender ResourceServerConfigurerAdapter y sobrescribir sus métodos. A continuación, se detallan las propiedades configurables.
Configuración de ResourceServerSecurityConfigurer:
- tokenServices: Una instancia de
ResourceServerTokenServicespara implementar el servicio de tokens. - tokenStore: Una instancia de
TokenStorepara especificar el acceso a los tokens. Es opcional cuando se configuratokenServices. - resourceId: El identificador (ID) de este servicio de recursos. Aunque es opcional, se recomienda establecerlo y validarlo en el servidor de autorización.
- Otras propiedades extendidas, como
tokenExtractor(extractor de tokens) para obtener el token de la solicitud.
Confgiuración de HttpSecurity: Similar a la configuración de Spring Security estándar.
- Definir los emparejadores de solicitudes para establecer las rutas de recursos protegidas. Por defecto, se protege toda la ruta del servicio de recursos.
- Establecer reglas de acceso para los recursos protegidos mediante
http.authorizeRequests(). - Configurar reglas de protección de permisos personalizadas adicionales a través de
HttpSecurity.
Ejemplo de configuración:
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerSecurity extends ResourceServerConfigurerAdapter {
private static final String IDENTIFICADOR_RECURSO = "mi_aplicacion";
@Autowired
private TokenStore almacenDeTokens;
@Override
public void configure(ResourceServerSecurityConfigurer config) {
config.resourceId(IDENTIFICADOR_RECURSO)
.tokenServices(obtenerServicioDeTokens())
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").access("#oauth2.hasScope('acceso_completo')")
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
@Primary
public ResourceServerTokenServices obtenerServicioDeTokens() {
DefaultTokenServices servicio = new DefaultTokenServices();
servicio.setTokenStore(almacenDeTokens);
return servicio;
}
}
El método obtenerServicioDeTokens() define cómo se procesan los tokens recibidos. Existen dos escenarios principales:
- Servidor de recursos y servidor de autorización en la misma aplicación: Se configura
DefaultTokenServicescon unTokenStorelocal para la validación de tokens. - Servicios separados (arquitectura de microservicios): Se utiliza
RemoteTokenServicespara validar tokens mediante una llamada al endpoint del servidor de autorización. Es necesario habilitar el endpoint de validación en el servidor de autorización:
@Override
public void configure(AuthorizationServerSecurityConfigurer seguridad) {
seguridad
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
}
Adicionalmente, en una configuración separada, se debe establecer un control de seguridad a nivel de aplicación:
@Configuration
public class SeguridadWeb extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/perfil/**").authenticated()
.anyRequest().permitAll();
}
}
Prueba del servidor de recursos:
Crear un controlador simple:
@RestController
@RequestMapping("perfil")
public class ControladorPerfil {
@GetMapping
@PreAuthorize("hasAuthority('rol_administrador')")
public Usuario obtenerPerfil() {
Usuario usuario = new Usuario();
usuario.setNombre("ejemplo_usuario");
return usuario;
}
}
Para probar, primero se obtiene un token (usando, por ejemplo, el flujo de contraseña) y luego se incluye en la solicitud al recurso protegido. Según la especificación OAuth 2.0:
- El token debe enviarse en el encabezado HTTP.
- El formato correcto es: Nombre del parámetro:
Authorization, Valor:Bearer <token>.
Las solicitudes con tokens inválidos o sin token serán rechazadas por el servidor.