Question

J'essaie de faire principalement l'authentification Digest (ou de base) à l'aide de RestTemplate et httpclient (4.x) .

Comme je n'ai pas trouvé d'exemples pertinents sur la façon de le faire, j'ai essayé différentes manières de raccorder les différents artefacts httpclient, sans succès - essentiellement, aucun en-tête Authentication n'est envoyétout.

Ma mise en œuvre actuelle est:

DefaultHttpClient newHttpClient = new DefaultHttpClient();
Credentials credentials = new UsernamePasswordCredentials( username, password );
AuthScope authScope = new AuthScope( host, port, AuthScope.ANY_REALM );
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials( authScope, credentials );
newHttpClient.setCredentialsProvider( credentialsProvider );

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory( newHttpClient );
restTemplate.setRequestFactory( requestFactory );

Y a-t-il quelque chose que je fais mal?Y a-t-il aussi un exemple de travail pour cela quelque part? Toute aide est appréciée. Merci.

Était-ce utile?

La solution

Essayez d'implémenter votre propre RequestFactory afin d'obtenir une authentification préemptive.

public class PreEmptiveAuthHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {

public PreEmptiveAuthHttpRequestFactory(DefaultHttpClient client) {
    super(client);
}

@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
    AuthCache authCache = new BasicAuthCache();
    BasicScheme basicAuth = new BasicScheme();
    HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort());
    authCache.put(targetHost, basicAuth);
    BasicHttpContext localcontext = new BasicHttpContext();
    localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

    return localcontext;
}
}

Ensuite, utilisez-le simplement:

HttpComponentsClientHttpRequestFactory requestFactory = new PreEmptiveAuthHttpRequestFactory( newHttpClient );

J'espère que cela aide


comment définir le nom d'utilisateur et le mot de passe (copié à partir du commentaire de @ bifur)

Vous pouvez utiliser UserNamePasswordCredentials

UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(getUsername(),getPassword()); 
client.getCredentialsProvider().setCredentials(new AuthScope(getHost(), getPort(), AuthScope.ANY_REALM), credentials); 

Et utilisez simplement le client dans l'usine précédente

HttpComponentsClientHttpRequestFactory requestFactory = new PreEmptiveAuthHttpRequestFactory(client);

Autres conseils

Avec la dernière version de Spring et HttpClient, ils ont rendu très facile les authentifications de base et digestes.

Remarque: j'utilise Spring Boot 2.x.x (Spring Framework 5.x.x) et HttpClient 4.5.x


Configurer RestTemplate

Nous pouvons configurer le RestTemplate pour effectuer une authentification de base ou condensée préemptive ou non préemptive (par défaut).

Configuration de l'authentification de base ou abrégée sans préemption

La configuration du RestTemplate pour utiliser l'authentification de base ou condensée non préemptive (c'est-à-dire initialement en train de lancer une demande de défi) est la même. Fournissez simplement le nom d'utilisateur et le mot de passe via la classe CredentialsProvider de la bibliothèque HttpClient.

HttpClient détectera automatiquement quel type d'authentification le serveur utilise en fonction de l'en-tête de réponse 401 de la demande initiale (demande de défi), donc pas besoin de faire de configuration spécifique au type d'authentification.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    Credentials credentials = new UsernamePasswordCredentials(username, password);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, credentials);

    HttpClient httpClient = HttpClients
            .custom()
            .setDefaultCredentialsProvider(credentialsProvider)
            .build();

    return builder
            .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient))
            .build();
}

Configuration de l'authentification de base préventive

Avec l'authentification de base préemptive, c'est encore plus facile, Spring la prend en charge immédiatement. Comme seuls le nom d'utilisateur et le mot de passe sont nécessaires, il est conseillé d'utiliser l'authentification de base préemptive pour supprimer le coût supplémentaire lié à la demande de défi.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
            .basicAuthorization(username, password)
            .build();
}

Configuration de l'authentification par résumé préventif

Spring ne prend pas en charge l'authentification condensée préemptive pour RestTemplate prête à l'emploi. Comme Digest auth nécessite le nonce et éventuellement d'autres données générées par le serveur (par exemple, opaques) en dehors du nom d'utilisateur et du mot de passe pour qu'il s'authentifie, au moins une demande de défi doit être faite.

Compte tenu de cela, il est toujours possible d'utiliser l'authentification condensée préemptive, mais en utilisant directement la bibliothèque de HttpClient. Si vous souhaitez toujours utiliser l'authentification préemptive digest avec RestTemplate, notez que certains problèmes peuvent survenir lors de la connexion à des applications non protégées par Spring Digest.

Reportez-vous aux réponses précédentes pour utiliser l'authentification condensée préemptive. Personnellement, je ne suggère pas d'utiliser l'authentification condensée préemptive avec RestTemplate étant donné la complexité et les problèmes qui peuvent être rencontrés. La principale motivation de l'utilisation de l'authentification condensée préemptive est à des fins de performances, donc à moins que vous ne fassiez de nombreux appels par requête, l'authentification condensée non préemptive pourrait être une meilleure option.


Envoyer la demande à l'aide de RestTemplate

Vous n'avez besoin d'aucune gestion spécifique au type d'authentification lorsque vous utilisez RestTemplate pour envoyer une requête. Peu importe que vous utilisiez une authentification préemptive ou non préemptive, le code d'envoi des requêtes sera simplement le même.

Exemple de requête GET

String response = restTemplate.getForObject(url, String.class);
JSONObject result = new JSONObject(response);

Exemple de demande POST

JSONObject body = new JSONObject();
// populate body

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> request = new HttpEntity<>(body, headers);
String response = restTemplate.postForObject(url, request, String.class);
JSONObject result = new JSONObject(response);

J'ai un peu modifié la réponse d'origine:

  • a ajouté la compatibilité https
  • éléments obsolètes mis à jour

    public class PreEmptiveAuthHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
    
        public PreEmptiveAuthHttpRequestFactory(HttpClient client) {
            super(client);
        }
    
        @Override
        protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
            AuthCache authCache = new BasicAuthCache();
            BasicScheme basicAuth = new BasicScheme();
            HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
            authCache.put(targetHost, basicAuth);
            HttpClientContext localContext = HttpClientContext.create();
            localContext.setAuthCache(authCache);
            return localContext;
        }
    }
    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top