Existe-t-il un moyen plus simple de configurer le client HTTP pour l’authentification de base préventive que ce qui est décrit ici ?
Dans la version précédente (3.x), il s'agissait d'un simple appel de méthode (par exemple, httpClient.getParams().setAuthenticationPreemptive(true)
).
La principale chose que je veux éviter consiste à ajouter BasicHttpContext à chaque méthode que j'exécute.
Réponses
Trop de publicités?Si vous souhaitez forcer HttpClient 4 à s'authentifier avec une seule requête, les opérations suivantes fonctionneront:
String username = ...
String password = ...
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));
Il est difficile de le faire sans passer à chaque fois dans un contexte, mais vous pouvez probablement le faire en utilisant un intercepteur de requêtes. Voici quelques codes que nous utilisons (trouvés dans leur JIRA, iirc):
// Pre-emptive authentication to speed things up
BasicHttpContext localContext = new BasicHttpContext();
BasicScheme basicAuth = new BasicScheme();
localContext.setAttribute("preemptive-auth", basicAuth);
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
(...)
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme avaialble yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if (authScheme != null) {
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if (creds == null) {
throw new HttpException("No credentials for preemptive authentication");
}
authState.setAuthScheme(authScheme);
authState.setCredentials(creds);
}
}
}
}
C'est la même solution que Mat Mannion, mais vous n'avez pas à mettre localContext à chaque demande. C'est plus simple, mais il ajoute authentification à TOUTES les demandes. Utile, si vous n'avez pas de contrôle sur les demandes individuelles, comme dans mon cas lors de l'utilisation d'Apache Solr, qui utilise HttpClient en interne.
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
(...)
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme avaialble yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if (creds == null)
throw new HttpException("No credentials for preemptive authentication");
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
Bien sûr, vous devez définir les informations d'identification fournisseur de:
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(url.getHost(), url.getPort()),
new UsernamePasswordCredentials(username, password))
L' AuthScope
ne doit pas contenir de domaine, car il n'est pas connu à l'avance.
Un peu tard pour le parti mais je suis tombé sur le fil en essayant de résoudre ceci pour la pré-autorisation par procuration d'une demande de publication. Pour ajouter à la réponse d'Adam, j'ai trouvé ce qui suit fonctionnait pour moi:
HttpPost httppost = new HttpPost(url);
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
Header bs = new BasicScheme().authenticate(creds, httppost);
httppost.addHeader("Proxy-Authorization", bs.getValue());
Pensée qui pourrait être utile pour quelqu'un d'autre qui se heurte à cela.
Je pense que le meilleur moyen peut être de le faire manuellement. J'ai ajouté la fonction suivante
Java classique:
import javax.xml.bind.DatatypeConverter;
...
private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException {
String encoded = DatatypeConverter.printBase64Binary((username + ":" + password).getBytes("UTF-8"));
http.addHeader("AUTHORIZATION", "Basic " + encoded);
}
HTTPRequestBase
peut être une instance de HttpGet
ou HttpPost
Android:
import android.util.Base64;
...
private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException {
String encoded = Base64.encodeToString((username + ":" + password).getBytes("UTF-8"), Base64.NO_WRAP);
http.addHeader("AUTHORIZATION", "Basic " + encoded);
}