Je travaille actuellement sur l'intégration d'une application tierce avec notre système de reporting local. Je voudrais implémenter REST appels avec authentification de base mais confrontés à des problèmes dans Spring 4.0.0. J'ai une solution simple qui fonctionne bien:
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<String> request = new HttpEntity<String>(headers);
final ResponseEntity<MyDto> response = restTemplate.exchange("myUrl", HttpMethod.GET, request, MyDto.class);
final MyDto dot = response.getBody();
mais je voulais réécrire ceci pour utiliser ClientHttpRequestFactory de la manière suivante:
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);
}
Ce code ne se compile pas car la classe CommonsClientHttpRequestFactory n'existe plus dans Spring 4.0.0. Quelqu'un connaît-il une solution alternative à cela? Je suis assez nouveau dans ce monde REST donc toute aide sera appréciée.
Pourquoi ne pas vérifier les API Spring 4 pour voir quelles classes implémentent l'interface requise, à savoir ClientHttpRequestFactory
?
Comme vous le verrez dans le Javadoc, vous voulez probablement HttpComponentsClientHttpRequestFactory
, qui utilise le client des HttpComponents d'Apache, le successeur des anciens communs HttpClient
.
Je sais que c'est une vieille question, mais je cherchais moi-même la réponse. Vous devez ajouter un intercepteur RestTemplate lors de la configuration du RestTemplate. Un exemple ci-dessous dans la configuration d'annotation:
@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 pour BasicAuthorizationInterceptor .
J'étais coincé là-dessus pendant quelques bonnes heures. Peut-être que cela aidera quelqu'un dans un avenir proche.
De http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ avec les modifications HttpClient 4.3 :
Spring 3.0, 3.1 et maintenant 4.x prennent en charge très bien les bibliothèques HTTP Apache :
CommonsClientHttpRequestFactory
intégré à la fin de HttpClient 3.x maintenant en vieHttpComponentsClientHttpRequestFactory
(prise en charge ajoutée dans le JIRA SPR- 618 )HttpComponentsAsyncClientHttpRequestFactory
Commençons par configurer les choses avec HttpClient 4 et Spring 4.
RestTemplate
nécessitera une fabrique de requêtes HTTP - une fabrique qui prend en charge l'authentification de base - jusqu'à présent, tout va bien. Cependant, l'utilisation directe du HttpComponentsClientHttpRequestFactory
existant sera difficile, car l'architecture de RestTemplate
a été conçue sans un bon support pour HttpContext
- un instrument pièce du puzzle. Nous devons donc sous-classer HttpComponentsClientHttpRequestFactory
et remplacer la méthode createHttpContext
: ( tiré de soluvas-framework sur 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/
*
* <p>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:
*
* <pre>
* final AuthHttpComponentsClientHttpRequestFactory requestFactory = new AuthHttpComponentsClientHttpRequestFactory(
* httpClient, Host, userName, password);
* final RestTemplate restTemplate = new RestTemplate(requestFactory);
* </pre>
*
* And the request:
*
* <pre>
* restTemplate.get("http://localhost:8080/spring-security-rest-template/api/foos/1", Foo.class);
* </pre>
*
* @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;
}
}
C'est ici - dans la création de HttpContext
- que le support d'authentification de base est intégré. Comme vous pouvez le voir, faire une authentification de base préemptive avec HttpClient 4.x est n peu lourd: les informations d'authentification sont mises en cache et le processus de la configuration de ce cache d'authentification est très manuel et peu intuitif .
Et avec cela, tout est en place - le RestTemplate
sera désormais en mesure de prendre en charge le schéma d'authentification de base ; un modèle d'utilisation simple serait:
final AuthHttpComponentsClientHttpRequestFactory requestFactory =
new AuthHttpComponentsClientHttpRequestFactory(
httpClient, Host, userName, password);
final RestTemplate restTemplate = new RestTemplate(requestFactory);
Et la demande:
restTemplate.get(
"http://localhost:8080/spring-security-rest-template/api/foos/1",
Foo.class);
Pour une discussion approfondie sur la façon de sécuriser le service REST lui-même, consultez cet article .
Depuis Spring 4.3.1, il existe un moyen plus simple d'utiliser BasicAuthorizationInterceptor
, qui est également indépendant du client http sous-jacent utilisé dans RestTemplate
.
L'exemple qui utilise RestTemplateBuilder
de spring-boot pour ajouter BasicAuthorizationInterceptor
à RestTemplate
:
@Configuration
public class AppConfig {
@Bean
public RestTemplate myRestTemplate(RestTemplateBuilder builder) {
return builder
.rootUri("http://my.cool.domain/api/")
.basicAuthorization("login", "password")
.build();
}
}
De cette façon toute demande envoyée à l'aide de l'instance de bean myRestTemplate
inclura l'en-tête d'autorisation de base donné. Veillez donc à ne pas utiliser la même instance de bean RestTemplate
pour envoyer des requêtes à des domaines étrangers. rootUri
est partiellement protégé contre cela, mais vous pouvez toujours transmettre l'URL absolue lors de la demande en utilisant l'instance RestTemplate
, alors soyez prudent!
Si vous n'utilisez pas spring-boot
, vous pouvez également ajouter manuellement cet intercepteur à votre RestTemplate
après cette réponse.
Si vous préférez simple plutôt que complexe, définissez simplement l'en-tête
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString("myuser:mypass".getBytes(Charset.forName("UTF-8"))));
HttpEntity<SomeBody> myRequest = new HttpEntity<>(mybody, headers);
restTemplate.postForEntity(someUrl, myRequest, null);
Je suis sûr qu'il existe une autre bibliothèque Base64 si l'encodage fourni avec le JDK est trop détaillé pour vous.
J'ai une autre solution pour définir l'authentification de base pour le modèle de repos personnalisé.
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<Header> 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;