使用Apache HttpClient进行抢占式基本身份验证4

yos*_*sis 48 java basic-authentication apache-commons-httpclient

是否有一种更简单的方法来设置http客户端以进行抢先式基本身份验证,而不是此处描述的内容?
在以前的版本(3.x)中,它曾经是一个简单的方法调用(例如httpClient.getParams().setAuthenticationPreemptive(true)).
我想避免的主要是将BasicHttpContext添加到我执行的每个方法.

Ada*_*kin 88

如果您希望强制HttpClient 4通过单个请求进行身份验证,则以下内容将起作用:

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

HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));
Run Code Online (Sandbox Code Playgroud)

  • 可能更好:`request.addHeader(BasicScheme.authenticate(creds,"US-ASCII",false));` (18认同)
  • 如果你想使用HttpClient 4.3中不弃用的方法:`request.addHeader(new BasicScheme().authenticate(creds,request,null))`.方法签名抛出`AuthenticationException`但它实际上从未发生过'BasicScheme`,所以你可以捕获异常并抛出新的AssertionError(e)`或者类似的东西. (7认同)
  • HttpClient 4中不推荐使用BasicScheme.authenticate. (3认同)

Mat*_*ion 23

如果没有每次传递上下文都很难做到这一点,但你可以通过使用请求拦截器来做到这一点.这是我们使用的一些代码(从他们的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);
            }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 在更新的版本中,`ClientContext`重命名为`HttpClientContext`,`ExecutionContext`重命名为`HttpCoreContext`,`authState.setXXX`方法替换为`authState.update(authScheme,creds)`. (4认同)

Oli*_*liv 18

这与Mat的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);
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

当然,您必须设置凭证提供程序:

httpClient.getCredentialsProvider().setCredentials(
                new AuthScope(url.getHost(), url.getPort()),
                new UsernamePasswordCredentials(username, password))
Run Code Online (Sandbox Code Playgroud)

AuthScope不能包含的境界,因为它是事先不知道.

  • 由于不推荐使用`authState.setAuthScheme()`和`authState.setCredentials()`,所以应该使用`authState.update(new BasicScheme(),creds);`. (7认同)
  • 同样在更新的版本中,`ClientContext`重命名为`HttpClientContext`,而`ExecutionContext`重命名为`HttpCoreContext`. (2认同)

小智 7

上面的很多答案都使用了弃用的代码.我使用的是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);
}
Run Code Online (Sandbox Code Playgroud)

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

    }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*han 6

派对有点晚了,但我试图通过线程试图解决这个问题,以便对帖子请求进行代理预授权.为了增加Adam的回复,我发现以下内容对我有用:

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

认为这可能对其他遇到此问题的人有所帮助.


Mar*_*cny 6

我认为最好的方法可能是手动完成.我添加了以下功能

经典Java:

import javax.xml.bind.DatatypeConverter;
Run Code Online (Sandbox Code Playgroud)

...

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);
    }
Run Code Online (Sandbox Code Playgroud)

HTTPRequestBase可以是HttpGet或的实例HttpPost

安卓:

import android.util.Base64;
Run Code Online (Sandbox Code Playgroud)

...

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);
}
Run Code Online (Sandbox Code Playgroud)