2012-04-27 12 views
34

Mam RESTful API Próbuję połączyć się z Androidem i RestTemplate. Wszystkie żądania do API są uwierzytelniane za pomocą uwierzytelniania HTTP, poprzez ustawienie nagłówków HttpEntity, a następnie za pomocą metody RestTemplate o nazwie exchange().Wykonywanie uwierzytelnionych żądań POST za pomocą Spring RestTemplate dla Androida

Wszystkie żądania GET działają w ten sposób, ale nie mogę wymyślić, jak wykonać uwierzytelnione żądania POST. postForObject i postForEntity obsługują POST, ale nie mają łatwego sposobu na ustawienie nagłówków uwierzytelniania.

Więc dla GET, to działa świetnie:

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

Ale POST najwyraźniej nie działają z exchange() jak nigdy nie wysyła niestandardowe nagłówki i nie widzę jak ustawić ciało żądania używając exchange().

Jaki jest najprostszy sposób na uwierzytelnianie żądań POST z RestTemplate?

+1

requestHeaders.setAuthorization (httpAuthentication) .. jego undefined..no metody takie jak setAuthorization .. – DEADEND

Odpowiedz

75

Ok znalazłem odpowiedź. exchange() to najlepszy sposób. Dziwnie, klasa HttpEntity nie ma metody setBody() (ma ona getBody()), ale nadal możliwe jest ustawienie treści żądania za pośrednictwem konstruktora.

// 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); 
+2

ona rzuca błąd TypeMismatch niezgodność typów: nie można przekonwertować z ResponseEntity do MyModel .. Chyba powinno być ResponseEntity Model = restTemplate.exchange ("/ api/url", HttpMethod.POST, httpEntity, MyModel.class); – Sid

+0

'MyModel myModel = restTemplate.exchange (completeServiceUrl, HttpMethod.GET, request, MyModel.class) .getBody()' pomoże rozwiązać problem, o którym wspomniałeś – Isank

+0

DZIĘKI. Kosztowało mnie to dwie godziny, aż natknąłem się na twój post. – guenhter

7

Bardzo przydatna miałem nieco inny scenariusz, w którym ja żądanie XML został sam korpus POST, a nie param. W tym celu można użyć następującego kodu - Posting as a answer na wszelki wypadek na korzyść kogokolwiek, kto ma podobny problem.

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

Nieco inne podejście:

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

Skąd pochodzi ObjectToPass od –

+0

@Ismail Iqbal - może to być dowolny obiekt z informacjami, które należy przekazać (na przykład prywatna Osoba john = Osoba ("Jan", 24);). Zostanie on przekonwertowany na json payload i przesłany na serwer poprzez treść żądania – Andrey

7

Byłem niedawno do czynienia z problemem, kiedy próbuje uzyskać uwierzytelnienie przeszłości podczas nawiązywania połączenia odpoczynku od Javy, a jednocześnie odpowiedzi w tym wątku (i inne wątki) pomogły, było jeszcze trochę prób i błędów związanych z działaniem.

Dla mnie działało kodowanie poświadczeń w Base64 i dodawanie ich jako nagłówków podstawowych uprawnień. Następnie dodałem je jako HttpEntity do restTemplate.postForEntity, co dało mi odpowiedź, której potrzebowałem.

Oto klasa napisałem tego w całości (rozszerzenie 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); 
    } 
} 
Powiązane problemy