【问题标题】:Apache HttpClient 4.4 Proxy Basic Auth: Multiple auth attempsApache HttpClient 4.4 代理基本身份验证:多次身份验证尝试
【发布时间】:2016-01-04 15:33:44
【问题描述】:

我正在尝试通过具有基本身份验证的代理使用 HTTP 客户端 4.4 发送请求。 如果我输入正确的凭据,则连接成功。

但如果我输入了错误的凭据,即使使用正确的凭据,以下所有其他连接尝试都会失败。

似乎一旦我们第一次提供了(错误的)凭据,就永远不会发送新的(正确或错误的)凭据。

你会看到有两个调用:

  1. 第一次调用,错误的代理凭据
  2. 第二次调用,正确的代理凭据

代码:

package test;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;

public class Main {

    private HttpClient client;
    private HttpClientContext context = HttpClientContext.create();

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
        System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
        System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "DEBUG");
        System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "ERROR");

        Main main = new Main();
        main.createHttpClient();
        main.send(true, "test", "wrong"); // 1st call, wrong credentials, if this call is removed, it works !
        main.send(true, "test", "correct"); // 2nd call, correct credentials
    }

    public void send(String username, String password) throws Exception {
        proxyAuthenticate(username, password);

        HttpUriRequest request = new HttpGet("https://the-backend.xyz");
        HttpResponse httpResponse = client.execute(request, context);
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        System.out.println("######################### " + statusCode);
    }

    public void createHttpClient() throws Exception {
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setProxy(new HttpHost("proxy.the-proxy.xyz", 1234));
        client = httpClientBuilder.build();
    }

    private void proxyAuthenticate(String username, String password) {
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
        AuthScope scope = new AuthScope("proxy.the-proxy.xyz", 1234);

        CredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(scope, credentials);

        context.setCredentialsProvider(provider);
    }

}

第一次尝试的日志(使用错误的代理凭据连接:两个 http 请求一个没有凭据,一个有凭据,都返回 407,看起来合乎逻辑):

2015/10/07 13:39:02:502 CEST [警告] BasicAuthCache - 意外的 I/O 序列化身份验证方案 java.io.NotSerializableException 时出错:test.Main at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) 在 java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) 在 java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) 在 java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) 在 java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) 在 java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) 在 org.apache.http.impl.client.BasicAuthCache.put(BasicAuthCache.java:107) 在 test.Main.proxyAuthenticate(Main.java:109) 在 test.Main.send(Main.java:56) 在 test.Main2.main(Main2.java:30)

2015/10/07 13:39:02:502 CEST [调试] RequestAddCookies - CookieSpec 已选择:默认 2015/10/07 13:39:02:502 CEST [DEBUG] PoolingHttpClientConnectionManager - 连接请求:[路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个] 2015/10/07 13:39:02:502 CEST [调试] PoolingHttpClientConnectionManager - 连接租用:[id:1][路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 1 条;总分配:1 of 3] 2015/10/07 13:39:02:502 CEST [调试] MainClientExec - 开放 联系 {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443 2015/10/07 13:39:02:502 CEST [调试] DefaultHttpClientConnectionOperator - 连接到 proxy.the-proxy.xyz/123.45.67.890:1234 2015/10/07 13:39:07:530 CEST [DEBUG] DefaultHttpClientConnectionOperator - 已建立连接 321.54.76.098:58216123.45.67.890:1234 2015/10/07 13:39:07:530 CEST [DEBUG] 标头 - http-outgoing-1 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:07:530 CEST [DEBUG] 标头 - http-outgoing-1 >> 主机: the-backend.xyz 2015/10/07 13:39:07:530 CEST [调试] 标头 - http-outgoing-1 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:07:530 CEST [DEBUG] 标头- http-outgoing-1 123.45.67.890:1234 2015/10/07 13:39:12:560 CEST [DEBUG] HttpAuthenticator - 生成对身份验证的响应 使用基本方案的挑战 2015/10/07 13:39:12:560 CEST [DEBUG] 标头 - http-outgoing-1 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:12:560 CEST [DEBUG] 标头 - http-outgoing-1 >> 主机: the-backend.xyz 2015/10/07 13:39:12:560 CEST [调试] 标头 - http-outgoing-1 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:12:560 CEST [DEBUG] 标头- http-outgoing-1 >> 代理授权:基本 xXXXxxXxXXXXXX 2015/10/07 13:39:12:561 CEST [DEBUG] 标头 - http-outgoing-1 http://proxy.the-proxy.xyz:1234 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭连接 2015/10/07 13:39:12:561 CEST [调试] MainClientExec - CONNECT 被拒绝 通过代理:HTTP/1.1 407 需要代理身份验证 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭连接 2015/10/07 13:39:12:561 CEST [调试] MainClientExec - 连接被丢弃 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭 连接 2015/10/07 13:39:12:561 CEST [调试] PoolingHttpClientConnectionManager - 连接已释放:[id: 1][路线: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个]

################### 407

第二次尝试的日志(使用正确的代理凭据连接:只有一个 http 请求,为什么没有第二次使用正确凭据的请求???):

2015/10/07 13:39:17:585 CEST [警告] BasicAuthCache - 意外的 I/O 序列化身份验证方案 java.io.NotSerializableException 时出错:test.Main at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) 在 java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) 在 java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) 在 java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) 在 java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) 在 java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) 在 org.apache.http.impl.client.BasicAuthCache.put(BasicAuthCache.java:107) 在 test.Main.proxyAuthenticate(Main.java:109) 在 test.Main.send(Main.java:56) 在 test.Main2.main(Main2.java:32)

2015/10/07 13:39:17:585 CEST [调试] RequestAddCookies - CookieSpec 已选择:默认 2015/10/07 13:39:17:585 CEST [DEBUG] PoolingHttpClientConnectionManager - 连接请求:[路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个] 2015/10/07 13:39:17:585 CEST [调试] PoolingHttpClientConnectionManager - 连接租用:[id: 2][route: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 1 条;总分配:1 of 3] 2015/10/07 13:39:17:585 CEST [调试] MainClientExec - 开放 联系 {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443 2015/10/07 13:39:17:585 CEST [调试] DefaultHttpClientConnectionOperator - 连接到 proxy.the-proxy.xyz/123.45.67.890:1234 2015/10/07 13:39:17:585 CEST [调试] DefaultHttpClientConnectionOperator - 已建立连接 321.54.76.098:58218123.45.67.890:1234 2015/10/07 13:39:17:586 CEST [DEBUG] 标头 - http-outgoing-2 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:17:586 CEST [DEBUG] 标头 - http-outgoing-2 >> 主机: the-backend.xyz 2015/10/07 13:39:17:586 CEST [调试] 标头 - http-outgoing-2 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:17:586 CEST [DEBUG] 标头- http-outgoing-2 http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个]

################### 407

知道为什么在第二次尝试时,它在没有身份验证(正常)的情况下尝试,服务器回复说需要基本身份验证,然后它没有尝试使用正确的凭据,而是关闭了连接。

谢谢!

更新:

如果我将 HttpClient(从 4.4)更改为 DefaultHttpClient(从 4.3)并调整这两种方法,它就可以工作。 请注意,在 4.3 中从客户端调用 getCredentialsProvider,在 4.4 中从上下文调用!!!

我第一次收到 407 状态代码,但第二次收到 200,这是我所期望的。

public void createHttpClient() throws Exception {
    client = new DefaultHttpClient();
    HttpHost proxy = new HttpHost("proxy.eurocontrol.be", 9513);
    ConnRouteParams.setDefaultProxy(client.getParams(), proxy);
}

private void proxyAuthenticate(String username, String password) {
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
    AuthScope scope = new AuthScope("proxy.eurocontrol.be", 9513);
    client.getCredentialsProvider().setCredentials(scope, credentials);
    // Called from client !!!!!!!!!!!!!!!!!
}

【问题讨论】:

    标签: java apache-httpclient-4.x


    【解决方案1】:

    代码的第一行清楚地表明两个请求都已发出。

    First at  - 2015/10/07 13:39:02:502
    
    Second at - 2015/10/07 13:39:17:585
    

    你打印的是服务器响应的状态码,见this和Http Status 407

    连你的日志都清楚地说明了

    Unexpected I/O error while serializing auth scheme java.io.NotSerializableException
    

    由于序列化也可能出现异常。

    【讨论】:

    • 您可以在第一个日志中看到,它在 13:39:07:530 再次尝试,这次使用凭据(13:39:12:560 CEST [DEBUG] 标头 - http-传出-1 >> 代理授权:基本 xXxxxXxXXXXXX)。关于 I/O 错误,这是一个警告。
    猜你喜欢
    • 1970-01-01
    • 2021-10-10
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    相关资源
    最近更新 更多