webentwicklung-frage-antwort-db.com.de

Präemptive Standardauthentifizierung mit Apache HttpClient 4

Gibt es eine einfachere Möglichkeit, den http-Client für die präemptive Basisauthentifizierung einzurichten, als mit here beschrieben?
In früheren Versionen (3.x) war dies früher ein einfacher Methodenaufruf (z. B. httpClient.getParams().setAuthenticationPreemptive(true)).
Die Hauptsache, die ich vermeiden möchte, ist das Hinzufügen von BasicHttpContext zu jeder von mir ausgeführten Methode.

47
yossis

Es ist schwierig, dies zu tun, ohne jedes Mal einen Kontext durchzugehen, aber Sie können dies wahrscheinlich mit einem Request Interceptor tun. Hier ist ein Code, den wir verwenden (gefunden von 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);
            }
        }

    }

}
22
Mat Mannion

Wenn Sie HttpClient 4 zur Authentifizierung mit einer einzigen Anforderung zwingen möchten, funktioniert Folgendes:

String username = ...
String password = ...
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);

HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));
87
Adam Batkin

Dies ist die gleiche Lösung wie bei Mat's Mannion, aber Sie müssen nicht localContext für jede Anforderung angeben. Es ist einfacher, fügt jedoch ALLEN Anforderungen Authentifizierung hinzu. Nützlich, wenn Sie keine individuellen Anforderungen haben, wie in meinem Fall bei der Verwendung von Apache Solr, das intern HttpClient verwendet.

import org.Apache.http.HttpException;
import org.Apache.http.HttpHost;
import org.Apache.http.HttpRequest;
import org.Apache.http.HttpRequestInterceptor;
import org.Apache.http.auth.AuthScope;
import org.Apache.http.auth.AuthState;
import org.Apache.http.auth.Credentials;
import org.Apache.http.client.CredentialsProvider;
import org.Apache.http.client.protocol.ClientContext;
import org.Apache.http.impl.auth.BasicScheme;
import org.Apache.http.protocol.ExecutionContext;
import org.Apache.http.protocol.HttpContext;

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

    }

}

Natürlich müssen Sie den Anmeldeinformationsanbieter festlegen:

httpClient.getCredentialsProvider().setCredentials(
                new AuthScope(url.getHost(), url.getPort()),
                new UsernamePasswordCredentials(username, password))

Die Variable AuthScope darf keinen Bereich enthalten, da dies nicht im Voraus bekannt ist.

17
Oliv

Viele der obigen Antworten verwenden veralteten Code. Ich verwende Apache SOLRJ Version 5.0.0 . Mein Code besteht aus 

private HttpSolrClient solrClient; 

private void initialiseSOLRClient() {
            URL solrURL = null;
            try {
                solrURL = new URL(urlString);
            } catch (MalformedURLException e) {
                LOG.error("Cannot parse the SOLR URL!!" + urlString);
                throw new SystemException("Cannot parse the SOLR URL!! " + urlString, e);
            }
            String Host = solrURL.getHost();
            int port = solrURL.getPort();
            AuthScope authScope = new AuthScope(Host, port);

    BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
    textEncryptor.setPassword("red bananas in the spring");
    String decryptPass = textEncryptor.decrypt(pass);
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, decryptPass);

    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(
            authScope,
            creds);

    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.addInterceptorFirst(new PreemptiveAuthInterceptor());
    builder.setDefaultCredentialsProvider(credsProvider);
    CloseableHttpClient httpClient = builder.build();

    solrClient = new HttpSolrClient(urlString, httpClient);
}

Der PreemptiveAuthInterceptor lautet nun wie folgt:

static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {

    public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
        AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
        // If no auth scheme available yet, try to initialize it
        // preemptively
        if (authState.getAuthScheme() == null) {
            CredentialsProvider credsProvider = (CredentialsProvider) 
                        context.getAttribute(HttpClientContext.CREDS_PROVIDER);
            HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_Host);
            AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
            Credentials creds = credsProvider.getCredentials(authScope);
            if(creds == null){

            }
            authState.update(new BasicScheme(), creds);
        }

    }
}
7
Brian teggart

Ich denke, der beste Weg ist, es einfach manuell zu machen. Ich habe die folgende Funktion hinzugefügt

Klassisches Java:

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 kann eine Instanz von HttpGet oder HttpPost sein

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);
}
6
Martin Konecny

Ein wenig zu spät zur Party, aber ich kam durch den Thread und versuchte, dies für die Proxy-Vorautorisierung einer Post-Anfrage zu lösen. Zu Adams Antwort kam noch Folgendes hinzu:

HttpPost httppost = new HttpPost(url);
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
Header bs = new BasicScheme().authenticate(creds, httppost);
httppost.addHeader("Proxy-Authorization", bs.getValue());

Ich denke, das könnte für alle anderen hilfreich sein, die auf dieses Problem stoßen.

6
Jonathan

Ich verwende diesen Code, basierend auf meinem Lesen von des HTTPClient 4.5-Dokuments :

HttpClientContext ctx = HttpClientContext.create()
ctx.setCredentialsProvider(new BasicCredentialsProvider())
ctx.setAuthCache(new BasicAuthCache())
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user, pass)
AuthScope authScope = new AuthScope(Host, port)
ctx.getCredentialsProvider.setCredentials(authScope, credentials)

// This part makes authentication preemptive:
HttpHost targetHost = new HttpHost(Host, port, scheme)
ctx.getAuthCache.put(targetHost, new BasicScheme())

... und stellen Sie sicher, dass Sie diesen Kontext immer an HTTPClient.execute() übergeben.

1
Chris Jones

Ich verstehe deinen abschließenden Kommentar nicht ganz. Es ist der HttpClient, der über all diese Maschinerie verfügt, um preemptive auth durchzuführen, und Sie müssen dies nur einmal tun (wenn Sie Ihren HttpClient erstellen und konfigurieren). Sobald Sie das getan haben, konstruieren Sie Ihre Methodeninstanzen auf dieselbe Weise wie immer. Sie fügen der Methode nicht "BasicHttpContext" hinzu.

Ich denke, Ihre beste Wette besteht darin, Ihr eigenes Objekt zu haben, das den gesamten für präemptive Auth erforderlichen Junk einrichtet und eine oder mehrere einfache Methoden zum Ausführen von Anforderungen für bestimmte HTTPMethod-Objekte enthält.

0

in Android kann Mat Mannions Antwort https nicht auflösen, senden Sie immer noch zwei Anfragen.

    public static DefaultHttpClient createProxyHttpClient() {
        try {
            final DefaultHttpClient client = createPlaintHttpClient();
            client.setRoutePlanner(new HttpRoutePlanner() {
                @Override
                public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
                    boolean isSecure = "https".equalsIgnoreCase(target.getSchemeName());
                    if (needProxy) {
                        Header header = isSecure ? ProxyUtils.createHttpsAuthHeader() : ProxyUtils.createAuthHeader();
                        if (isSecure) {
                            client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT + "\r\n" + header.getName() + ":" + header.getValue());
                        } else {
                            client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
                            if (request instanceof RequestWrapper) {
                                request = ((RequestWrapper) request).getOriginal();
                            }
                            request.setHeader(header);
                        }
                        String Host = isSecure ? ProxyUtils.SECURE_Host : ProxyUtils.Host;
                        int port = isSecure ? ProxyUtils.SECURE_PORT : ProxyUtils.PORT;
                        return new HttpRoute(target, null,  new HttpHost(Host, port), isSecure);
                    } else {
                        client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
                        return new HttpRoute(target, null, isSecure);
                    }
                }
            });
            return client;
        } catch (Exception e) {
            e.printStackTrace();
            return new DefaultHttpClient();
        }
    }

public static DefaultHttpClient createPlaintHttpClient() {
       try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
            PlainSSLSocketFactory socketFactory = new PlainSSLSocketFactory(trustStore);
            socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            BasicHttpParams params = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(params, 30000);
            HttpConnectionParams.setSoTimeout(params, 30000);
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", socketFactory, 443));
            ThreadSafeClientConnManager ccm = new ThreadSafeClientConnManager(params, registry);
            HttpClientParams.setCookiePolicy(params, CookiePolicy.BROWSER_COMPATIBILITY);
            final DefaultHttpClient client = new DefaultHttpClient(ccm, params);
            client.setRoutePlanner(new HttpRoutePlanner() {
        @Override
        public HttpRoute determineRoute(HttpHost target, HttpRequest arg1, HttpContext arg2) throws HttpException {
               client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
            return new HttpRoute(target, null, "https".equalsIgnoreCase(target.getSchemeName()));
        }
        });
            return client;
        } catch (Exception e) {
            e.printStackTrace();
            return new DefaultHttpClient();
        }
}
0
ljian