Realizar solicitudes POST autenticadas con Spring RestTemplate para Android


Tengo una API RESTful con la que estoy tratando de conectarme a través de Android y RestTemplate. Todas las solicitudes a la API se autentican con autenticación HTTP, a través de la configuración de las cabeceras de la HttpEntity y luego utilizando el método exchange() de RestTemplate.

Todas las solicitudes GET funcionan muy bien de esta manera, pero no puedo averiguar cómo realizar solicitudes POST autenticadas. postForObject y postForEntity manejan mensajes, pero no tienen una manera fácil de establecer los encabezados de autenticación.

Así que para GETs, esto funciona genial:

HttpAuthentication httpAuthentication = new HttpBasicAuthentication("username", "password");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(httpAuthentication);

HttpEntity<?> httpEntity = new HttpEntity<Object>(requestHeaders);

MyModel[] models = restTemplate.exchange("/api/url", HttpMethod.GET, httpEntity, MyModel[].class);

Pero las publicaciones aparentemente no funcionan con exchange() ya que nunca envía los encabezados personalizados y no veo cómo configurar el cuerpo de la solicitud usando exchange().

¿Cuál es la forma más fácil de realizar solicitudes POST autenticadas desde RestTemplate?

Author: Nick Daugherty, 2012-04-28

4 answers

Ok encontró la respuesta. exchange() es la mejor manera. Curiosamente la clase HttpEntity no tiene un método setBody() (tiene getBody()), pero todavía es posible establecer el cuerpo de la solicitud, a través del constructor.

// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();     

body.add("field", "value");

// Note the body object as first parameter!
HttpEntity<?> httpEntity = new HttpEntity<Object>(body, requestHeaders);

MyModel model = restTemplate.exchange("/api/url", HttpMethod.POST, httpEntity, MyModel.class);
 87
Author: Nick Daugherty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-19 02:25:53

Un enfoque ligeramente diferente:

MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("HeaderName", "value");
headers.add("Content-Type", "application/json");

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(objectToPass, headers);

restTemplate.postForObject(url, request, ClassWhateverYourControllerReturns.class);
 16
Author: Andrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-12 08:22:48

Recientemente estaba lidiando con un problema cuando estaba tratando de pasar la autenticación mientras hacía una llamada REST desde Java, y mientras que las respuestas en este hilo (y otros hilos) ayudaron, todavía había un poco de ensayo y error involucrado en conseguir que funcione.

Lo que funcionó para mí fue codificar credenciales en Base64 y agregarlas como encabezados de Autorización básicos. Luego los agregué como HttpEntity a restTemplate.postForEntity, lo que me dio la respuesta que necesitaba.

Aquí está la clase que escribí para esto en su totalidad (extendiendo RestTemplate):

public class AuthorizedRestTemplate extends RestTemplate{

    private String username;
    private String password;

    public AuthorizedRestTemplate(String username, String password){
        this.username = username;
        this.password = password;
    }

    public String getForObject(String url, Object... urlVariables){
        return authorizedRestCall(this, url, urlVariables);
    }

    private String authorizedRestCall(RestTemplate restTemplate, 
            String url, Object... urlVariables){
        HttpEntity<String> request = getRequest();
        ResponseEntity<String> entity = restTemplate.postForEntity(url, 
                request, String.class, urlVariables);
        return entity.getBody();
    }

    private HttpEntity<String> getRequest(){
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + getBase64Credentials());
        return new HttpEntity<String>(headers);
    }

    private String getBase64Credentials(){
        String plainCreds = username + ":" + password;
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
        return new String(base64CredsBytes);
    }
}
 8
Author: zacran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-10 13:28:44

Muy útil Tuve un escenario ligeramente diferente en el que el xml de solicitud era en sí el cuerpo del POST y no un param. Para eso se puede usar el siguiente código: Publicar como respuesta en caso de que alguien más tenga un problema similar se beneficie.

    final HttpHeaders headers = new HttpHeaders();
    headers.add("header1", "9998");
    headers.add("username", "xxxxx");
    headers.add("password", "xxxxx");
    headers.add("header2", "yyyyyy");
    headers.add("header3", "zzzzz");
    headers.setContentType(MediaType.APPLICATION_XML);
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
    final HttpEntity<MyXmlbeansRequestDocument> httpEntity = new HttpEntity<MyXmlbeansRequestDocument>(
            MyXmlbeansRequestDocument.Factory.parse(request), headers);
    final ResponseEntity<MyXmlbeansResponseDocument> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity,MyXmlbeansResponseDocument.class);
    log.info(responseEntity.getBody());
 7
Author: Soumya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-24 13:07:29