web-dev-qa-db-fra.com

Création de requêtes authentifiées POST) avec Spring RestTemplate pour Android

J'ai une API RESTful avec laquelle je tente de me connecter via Android et RestTemplate. Toutes les demandes de l'API sont authentifiées avec une authentification HTTP, en définissant les en-têtes de HttpEntity, puis en utilisant exchange() méthode.

Toutes les requêtes GET fonctionnent parfaitement de cette façon, mais je ne vois pas comment accomplir les requêtes authentifiées POST. postForObject et postForEntity, mais elles ne sont pas simples. définir les en-têtes d'authentification.

Donc, pour GETs, cela fonctionne très bien:

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);

Mais les POST ne fonctionnent apparemment pas avec exchange() car il n'envoie jamais les en-têtes personnalisés et je ne vois pas comment définir le corps de la requête à l'aide de exchange().

Quel est le moyen le plus simple de faire des requêtes authentifiées POST) depuis RestTemplate?

52
Nick Daugherty

Ok a trouvé la réponse. exchange() est le meilleur moyen. Bizarrement, la classe HttpEntity n'a pas de méthode setBody() (elle a getBody()), mais il est toujours possible de définir le corps de la requête, via le constructeur.

// 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);
105
Nick Daugherty

Approche légèrement différente:

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);
21
Andrey

Je m'occupais récemment d'un problème lorsque j'essayais de passer l'authentification en passant un appel depuis REST) à partir de Java. peu d'essais et d'erreurs impliqués pour le faire fonctionner.

Ce qui a fonctionné pour moi était le codage des informations d’identification dans Base64 et en les ajoutant comme en-têtes d'autorisation de base. Je les ai ensuite ajoutés en tant que HttpEntity à restTemplate.postForEntity, qui m'a donné la réponse dont j'avais besoin.

Voici le cours que j'ai écrit pour cela en entier (extension de 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);
    }
}
10
zacran

Très utile, j’avais un scénario légèrement différent dans lequel la requête xml était elle-même le corps du POST et non un paramètre. Pour cela, le code suivant peut être utilisé - Publier comme réponse au cas où quiconque ayant le même problème en bénéficiera.

    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());
8
Soumya