Autenticação básica do Spring 4.0.0 com RestTemplate

No momento, estou trabalhando na integração de um aplicativo de terceiros com nosso sistema de relatórios local. Eu gostaria de implementar chamadas REST com autenticação básica, mas enfrentando problemas no Spring 4.0.0. Eu tenho uma solução simples que funciona bem:

final RestTemplate restTemplate = new RestTemplate(); final String plainCreds = "username:password"; final byte[] plainCredsBytes = plainCreds.getBytes(); final byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); final String base64Creds = new String(base64CredsBytes); final HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + base64Creds); final HttpEntity request = new HttpEntity(headers); final ResponseEntity response = restTemplate.exchange("myUrl", HttpMethod.GET, request, MyDto.class); final MyDto dot = response.getBody(); 

mas queria rewrite isso para usar ClientHttpRequestFactory da seguinte maneira:

 final RestTemplate restTemplate = new RestTemplate(createSecureTransport("username", "password")); private ClientHttpRequestFactory createSecureTransport(final String username, final String password) { final HttpClient client = new HttpClient(); final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password); client.getState().setCredentials(new AuthScope(null, 9090, AuthScope.ANY_REALM), credentials); return new CommonsClientHttpRequestFactory(client); } 

Este código não está compilando como a class CommonsClientHttpRequestFactory não existe mais no Spring 4.0.0. Alguém conhece alguma solução alternativa para isso? Eu sou muito novo neste mundo REST, portanto, qualquer ajuda será apreciada.

Por que não verificar as APIs do Spring 4 para ver quais classs implementam a interface necessária, ou seja, ClientHttpRequestFactory ?

Como você verá no Javadoc, o mais provável é que você queira HttpComponentsClientHttpRequestFactory , que usa o cliente do HttpComponents do Apache, o sucessor do antigo Common HttpClient .

Eu sei que esta é uma questão antiga, mas eu estava procurando a resposta para mim mesmo. Você precisa adicionar um interceptador RestTemplate ao configurar o RestTemplate. Um exemplo abaixo na configuração de anotação:

 @Bean public RestTemplate restTemplate() { final RestTemplate restTemplate = new RestTemplate(); restTemplate.setMessageConverters(Arrays.asList( new FormHttpMessageConverter(), new StringHttpMessageConverter() )); restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("client", "secret")); return restTemplate; } 

Javadoc para BasicAuthorizationInterceptor .

Fiquei preso nisso por umas boas poucas horas. Talvez isso ajude alguém no futuro próximo.

De http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ com o HttpClient 4.3 edits :

Tanto o Spring 3.0 como o 3.1 e agora o 4.x têm um suporte muito bom para as bibliotecas HTTP do Apache :

  1. spring 3.0 , o CommonsClientHttpRequestFactory integrado com o agora terminado HttpClient 3.x
  2. O Spring 3.1 introduziu suporte para o atual HttpClient 4.x via HttpComponentsClientHttpRequestFactory (suporte incluído no JIRA SPR-6180 )
  3. O Spring 4.0 introduziu o suporte asynchronous por meio do HttpComponentsAsyncClientHttpRequestFactory

Vamos começar a configurar as coisas com o HttpClient 4 e o Spring 4.

O RestTemplate exigirá uma fábrica de solicitações HTTP – uma fábrica que suporte a autenticação básica – até agora, tudo bem. No entanto, usar o HttpComponentsClientHttpRequestFactory existente diretamente será difícil, já que a arquitetura do RestTemplate foi projetada sem um bom suporte para o HttpContext – uma peça instrumental do quebra-cabeça. Assim, precisaremos criar a subclass HttpComponentsClientHttpRequestFactory e replace o método createHttpContext : ( extraído do framework soluvas no GitHub )

 package org.soluvas.commons.util; import java.net.URI; import javax.annotation.Nullable; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.HttpClient; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.protocol.HttpContext; import org.springframework.http.HttpMethod; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; /** * From http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ * * 

And with that, everything is in place – the {@link RestTemplate} will now be able to support the Basic Authentication scheme; a simple usage pattern would be: * *

 * final AuthHttpComponentsClientHttpRequestFactory requestFactory = new AuthHttpComponentsClientHttpRequestFactory( * httpClient, host, userName, password); * final RestTemplate restTemplate = new RestTemplate(requestFactory); * 

* * And the request: * *

 * restTemplate.get("http://localhost:8080/spring-security-rest-template/api/foos/1", Foo.class); * 

* * @author anton */ public class AuthHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory { protected HttpHost host; @Nullable protected String userName; @Nullable protected String password; public AuthHttpComponentsClientHttpRequestFactory(HttpHost host) { this(host, null, null); } public AuthHttpComponentsClientHttpRequestFactory(HttpHost host, @Nullable String userName, @Nullable String password) { super(); this.host = host; this.userName = userName; this.password = password; } public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host) { this(httpClient, host, null, null); } public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host, @Nullable String userName, @Nullable String password) { super(httpClient); this.host = host; this.userName = userName; this.password = password; } @Override protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { // Create AuthCache instance AuthCache authCache = new BasicAuthCache(); // Generate BASIC scheme object and add it to the local auth cache BasicScheme basicAuth = new BasicScheme(); authCache.put(host, basicAuth); // Add AuthCache to the execution context HttpClientContext localcontext = HttpClientContext.create(); localcontext.setAuthCache(authCache); if (userName != null) { BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(new AuthScope(host), new UsernamePasswordCredentials(userName, password)); localcontext.setCredentialsProvider(credsProvider); } return localcontext; } }

É aqui – na criação do HttpContext – que o suporte de autenticação básica está embutido. Como você pode ver, fazer a Autenticação Básica preemptiva com HttpClient 4.x é um fardo : as informações de autenticação são armazenadas em cache eo processo de configurar esse cache de autenticação é muito manual e não intuitivo .

E com isso, tudo está no lugar – o RestTemplate agora será capaz de suportar o esquema de Autenticação Básica ; um padrão de uso simples seria:

 final AuthHttpComponentsClientHttpRequestFactory requestFactory = new AuthHttpComponentsClientHttpRequestFactory( httpClient, host, userName, password); final RestTemplate restTemplate = new RestTemplate(requestFactory); 

E o pedido:

 restTemplate.get( "http://localhost:8080/spring-security-rest-template/api/foos/1", Foo.class); 

Para uma discussão aprofundada sobre como proteger o Serviço REST, confira este artigo .

Se você preferir o simples mais complexo, basta definir o header

  HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString("myuser:mypass".getBytes(Charset.forName("UTF-8")))); HttpEntity myRequest = new HttpEntity<>(mybody, headers); restTemplate.postForEntity(someUrl, myRequest, null); 

Tenho certeza de que há alguma outra biblioteca Base64 disponível se a codificação fornecida com o JDK for muito detalhada para você.

Desde o Spring 4.3.1, há uma maneira mais simples de usar BasicAuthorizationInterceptor , que também é independente do cliente HTTP subjacente usado em RestTemplate .

O exemplo que usa o RestTemplateBuilder partir do spring-boot para adicionar BasicAuthorizationInterceptor ao RestTemplate :

 @Configuration public class AppConfig { @Bean public RestTemplate myRestTemplate(RestTemplateBuilder builder) { return builder .rootUri("http://my.cool.domain/api/") .basicAuthorization("login", "password") .build(); } } 

Dessa forma, qualquer solicitação enviada usando a instância do bean myRestTemplate includeá o header de autorização básico fornecido. Portanto, tenha cuidado para não usar a mesma instância do bean RestTemplate para enviar solicitações para domínios externos. O rootUri é parcialmente protegido contra isso, mas você sempre pode passar o URL absoluto ao fazer o pedido usando a instância RestTemplate , então tenha cuidado!

Se você não estiver usando o spring-boot , você também pode adicionar manualmente este interceptador ao seu RestTemplate seguindo esta resposta.

Eu tenho outra solução para definir autenticação básica para modelo de descanso personalizado.

 RestTemplate restTemplate = new RestTemplate(); HttpHost proxy =null; RequestConfig config=null; String credentials = this.env.getProperty("uname") + ":" + this.env.getProperty("pwd"); String encodedAuthorization = Base64.getEncoder().encodeToString(credentials.getBytes()); Header header = new BasicHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedAuthorization); List
headers = new ArrayList<>(); headers.add(header); // if we need proxy if(Boolean.valueOf(env.getProperty("proxyFlag"))){ proxy = new HttpHost(this.env.getProperty("proxyHost"), Integer.parseInt(env.getProperty("proxyPort")), "http"); config= RequestConfig.custom().setProxy(proxy).build(); }else{ config= RequestConfig.custom().build(); } CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config) .setDefaultHeaders(headers).build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); restTemplate.setRequestFactory(factory); return restTemplate;