具有身份验证的Apache HttpClient Socks5代理

时间:2018-07-10 15:30:06

标签: java authentication proxy apache-httpclient-4.x socks

我正在尝试使用Socks5代理服务器来请求对某个目标(主机)的请求,该目标需要Java应用程序中的代理。我正在使用Apache Http库(4.5.4版)。我有许多其他不需要代理的目标,因此对我来说,在整个应用程序中全局设置代理不是一个选择。因此,我为HttpClient的某个实例设置了代理。代理要求使用登录名和密码进行身份验证。

我的解决方案基于此question,另外还按照documentation中所述添加了身份验证参数。

这是我的代码:

private void sendSocks5Request(StringEntity requestEntity) throws Exception {

        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new MyConnectionSocketFactory(SSLContexts.createSystemDefault()))
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);

        Credentials credentials = new UsernamePasswordCredentials("proxy_user","proxy_pass");
        AuthScope authScope = new AuthScope("my.proxy.com", 1080);
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(authScope, credentials);

        CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(cm)
                .setDefaultCredentialsProvider(credsProvider)
                .build();

        try {
            InetSocketAddress socksaddr = new InetSocketAddress("my.proxy.com", 1080);
            HttpClientContext context = HttpClientContext.create();
            context.setAttribute("socks.address", socksaddr);

            HttpHost target = new HttpHost("api.telegram.org", 80, "https");
            HttpPost request = new HttpPost("/bot<bot_token_here>");
            request.setEntity(requestEntity);

            System.out.println("Executing request " + request + " to " + target + " via SOCKS proxy " + socksaddr);
            CloseableHttpResponse response = httpclient.execute(target, request, context);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                EntityUtils.consume(response.getEntity());
            } catch (Exception ex) {
                ex.getMessage();
            } finally {
                response.close();
            }
        } catch (Exception ex) {
            ex.getMessage();
        } finally {
            httpclient.close();
        }
}

代理似乎可以工作,但是出现Authentication failed错误。代理服务器本身上的日志显示,提供的身份验证不包含proxy_user用户,而是本机的系统用户。因此,看起来HttpClient会忽略提供的凭据,并从系统中获取它。

我在做什么错了?

1 个答案:

答案 0 :(得分:0)

我花了几天的时间来解决同样的问题。 对我来说,最简单的方法是使用Java的float64 只需在Authenticator之前添加以下代码即可:

execute

之后,套接字应发送您的凭据。如果您有兴趣,可以调试Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(proxyUser, proxyPassword.toCharArray()); } }); 方法。

我尝试使用许多其他方法,但是它们都不对我有用。我假设java.net.SocksSocketImpl#authenticate(byte, java.io.InputStream, java.io.BufferedOutputStream, long)setDefaultCredentialsProvider而不是target上响应认证请求。我还没有调试那么深。我仍然试图找出如何更优雅地解决此问题的方法。让我知道您是否会找到更好的解决方案。