Invocar a un servicio REST securizado, con el soporte de plantillas Spring.
0. Índice de contenidos.
1. Introducción
En este tutorial vamos a exponer cómo realizar una invocación a un servicio REST con el soporte de plantillas de Spring y cómo configurar el cliente http para que la invocación se realice con un usuario y contraseña de paso.
El escenario es el de un servicio REST securizado como el que proponíamos en el tutorial de múltiples contextos de seguridad con Spring Security y un cliente que realiza invocaciones a uno de esos servicios.
Disponiendo de una versión 3.1 de Spring podemos hacer uso del soporte de plantillas para realizar la invocación y para la configuración de autenticación podemos apoyarnos en la librería de Apache commons-httpclient.
2. Entorno.
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 15′ (2.4 GHz Intel Core i7, 8GB DDR3 SDRAM).
- Sistema Operativo: Mac OS X Lion 10.7.4
- Spring Security 3.1.0.
3. Configuración.
Suponiendo que hacemos uso de maven, esta sería la configuración de dependencias de nuestro pom.xml:
<dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.1.0.RELEASE</version> </dependency>
En el contenido de nuestro applicationContext.xml de spring, la configuración de la autenticación, el cliente http, la factoría de peticiones http y la plantilla que nos da soporte para REST sería la siguiente:
<context:property-placeholder location="classpath*:app.properties" /> <bean id="frontCredentials" class="org.apache.commons.httpclient.UsernamePasswordCredentials"> <constructor-arg value="${security.front.ws.userName}" /> <constructor-arg value="${security.front.ws.password}" /> </bean> <bean id="frontHttpState" class="com.autentia.tutoriales.ws.rest.CustomHttpState"> <property name="credentials" ref="frontCredentials" /> </bean> <bean id="frontHttpClient" class="org.apache.commons.httpclient.HttpClient"> <property name="state" ref="frontHttpState" /> </bean> <bean id="frontHttpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory"> <constructor-arg ref="frontHttpClient" /> </bean> <bean id="frontRestTemplate" class="org.springframework.web.client.RestTemplate"> <constructor-arg ref="frontHttpClientFactory" /> </bean>
El servicio frontRestTemplate nos va a permitir invocar a servicios REST, a través de una factoría que usa el cliente http al que se inyectan las credenciales configuradas mediante el servicio UsernamePasswordCredential y encapsuladas en un servicio propio CustomHttpState. El usuario y contraseña se obtienen de un fichero de propiedades leido a través de un property-placeholder.
El código del servicio que encapsula las credenciales no es más que una clase que extiende de HttpState:
package com.autentia.tutoriales.ws.rest; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.auth.AuthScope; public class CustomHttpState extends HttpState { /** * Set credentials property. * * @param credentials * @see #setCredentials(org.apache.commons.httpclient.auth.AuthScope, org.apache.commons.httpclient.Credentials) */ public void setCredentials(final Credentials credentials) { super.setCredentials(AuthScope.ANY, credentials); } }
La necesidad de esta clase viene dada porque la clase HttpState no está pensada para ser un POJO y el método setCredentials recibe dos parámetros.
4. Invocación.
Una vez disponemos del servicio configurado, podemos inyectar el mismo en cualquier bean manejado por spring e invocar al servicio REST de la siguiente forma:
import java.io.Serializable; import javax.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class CacheRemoteManager implements Serializable { @Resource(name="frontRestTemplate") private RestTemplate restTemplate; public String[] getRegionsAvailable() { return restTemplate.getForObject("https://mi-comercio-online/ws/cache/names"), String[].class); } }
El servicio REST podría ser un ejemplo de recuperación de todas las regiones de cache definidas para el frontal.
Hacer uso de la plantilla es muy sencillo, no tenemos más que establecer la url del servicio e indicar el tipo de objeto en el que la plantilla intentará mapear el resultado de la invocación al mismo. Por defecto, se usa JSON como protocolo de transporte, pero para nosotros es transparente, porque la plantilla se encarga de des-serializar la respuesta al tipo de objeto que le indiquemos.
Del lado del servicio invocado o a invocar tendríamos una configuración similar a la siguiente, con el soporte de Spring MVC:
@Controller @RequestMapping("/cache") public class CacheResource { @Autowired public CacheResource(CacheLocalManager cacheManager) { this.cacheManager = cacheManager; } @RequestMapping(value = "/names", method = RequestMethod.GET) public @ResponseBody Collection<String> getNames() { return cacheManager.getNames(); } }
Para más información, me remito al tutorial de Spring + REST + JSON = SOAUI
5. Referencias.
- https://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=springRestJson
- http://aruld.info/resttemplate-the-spring-way-of-accessing-restful-services/
- http://stackoverflow.com/questions/4615039/spring-security-authentication-using-resttemplate
6. Conclusiones.
El uso de pantillas en Spring es extremadamente sencillo y pontente, si además nos apoyamos en las librerías de Apache Commons, habremos hecho una apuesta segura.
Un saludo.
Jose