web-dev-qa-db-ja.com

Apache HttpClient 4を使用した先制基本認証

here で説明したものよりも、先制の基本認証用にhttpクライアントをセットアップする簡単な方法はありますか?
以前のバージョン(3.x)では、以前は単純なメソッド呼び出しでした(たとえば、httpClient.getParams().setAuthenticationPreemptive(true))。
避けたい主なことは、実行する各メソッドにBasicHttpContextを追加することです。

48
yossis

毎回コンテキストを渡さずにこれを行うことは困難ですが、おそらくリクエストインターセプターを使用して行うことができます。使用するコードは次のとおりです(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);
            }
        }

    }

}
23
Mat Mannion

HttpClient 4が単一の要求で認証されるように強制する場合、次のように機能します。

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

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

これはMat's Mannionのソリューションと同じソリューションですが、各リクエストにlocalContextを配置する必要はありません。よりシンプルですが、すべてのリクエストに認証を追加します。 HttpClientを内部的に使用するApache Solrを使用する場合のように、個々のリクエストを制御できない場合に役立ちます。

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

    }

}

もちろん、資格情報プロバイダーを設定する必要があります。

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

AuthScopeにはレルムを含めることはできません。事前に知られていないためです。

18
Oliv

上記の回答の多くは非推奨のコードを使用しています。 Apache SOLRJバージョン5.0.0を使用しています。私のコードは

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

PreemptiveAuthInterceptorは次のようになりました。

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

最善の方法は、手動で行うことだと思います。次の機能を追加しました

クラシック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は、HttpGetまたはHttpPostのインスタンスにすることができます

アンドロイド:

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

パーティーに少し遅れましたが、ポストリクエストのプロキシ事前承認のためにこれを解決しようとしてスレッドに出くわしました。アダムの応答に追加するために、私は次のことがうまくいったことがわかりました。

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

これに出くわす他の人にとっては役に立つかもしれないと思った。

6
Jonathan

HTTPClient 4.5 docs :の読みに基づいて、このコードを使用しています。

_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())
_

...そのコンテキストを常にHTTPClient.execute()に渡すようにしてください。

1
Chris Jones

最後のコメントは得られません。プリエンプティブ認証を行うためのすべての機構を備えているのはHttpClientであり、一度だけ(HttpClientを構築および構成するときに)行う必要があります。それが完了したら、いつもと同じ方法でメソッドインスタンスを構築します。メソッドに「BasicHttpContextを追加する」ことはありません。

最善の策は、プリエンプティブ認証に必要なすべてのジャンクを設定する独自のオブジェクトを用意し、特定のHTTPMethodオブジェクトでリクエストを実行するための簡単なメソッドを用意することです。

0

androidでは、Mat Mannionの答えはhttpsを解決できません、まだ2つのリクエストを送信します、以下のようにすることができます、トリックはuser-agentにauthHeaderを追加することです:

    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