HttpsURLConnection通过代理访问如何设置Proxy-Authorization

炎黄伙哥
  • 65

在代码里已经设置了conn.setRequestProperty("Proxy-Authorization", auth);但这个设置只对正式的请求有效,通过wireshark发现在发出正式请求前,会先发出一个CONNECT请求来建立Tunnel,而这个CONNECT请求是没有设置Proxy-Authorization请求头的,导致应答返回407.通过分析源码找到如下代码段:

private void setPreemptiveProxyAuthentication(MessageHeader requests) throws IOException {
    AuthenticationInfo pauth
        = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
                                          http.getProxyPortUsed());
    if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
        String value;
        if (pauth instanceof DigestAuthentication) {
            DigestAuthentication digestProxy = (DigestAuthentication) pauth;
            if (tunnelState() == TunnelState.SETUP) {
                value = digestProxy
                    .getHeaderValue(connectRequestURI(url), HTTP_CONNECT);
            } else {
                value = digestProxy.getHeaderValue(getRequestURI(), method);
            }
        } else {
            value = pauth.getHeaderValue(url, method);
        }

        // Sets "Proxy-authorization"
        requests.set(pauth.getHeaderName(), value);
        currentProxyCredentials = pauth;
    }
}

会有一个缓存来根据proxyHost和proxyPort来缓存其验证信息,但不知道这个验证信息该如何正确设置。继续分析源码,再第一次请求失败后会判断是否为407,如果是的话会通过Authenticator获取用户名密码信息并缓存,这样似乎可以通过

    Authenticator authenticator = new Authenticator() {
        public PasswordAuthentication getPasswordAuthentication() {
            return (new PasswordAuthentication("admin", "Admin@2018!".toCharArray()));
        }
    };
    Authenticator.setDefault(authenticator);

来设置用户名和密码,发送第一次的时候回返回407,然后根据应答和Authenticator创建并缓存验证信息,那么第二次应该会成功,但是如下的测试代码两次全都失败了

public static void main(String[] a) {

    Authenticator authenticator = new Authenticator() {

        public PasswordAuthentication getPasswordAuthentication() {
            return (new PasswordAuthentication("admin", "admin".toCharArray()));
        }
    };
    Authenticator.setDefault(authenticator);
    
    try {
        testSend();
    } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) {
        e.printStackTrace();
    }
    try {
        testSend();
    } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) {
        e.printStackTrace();
    }
}

private static void testSend() throws KeyManagementException, NoSuchAlgorithmException, IOException {
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[] { new DisabledValidationTrustManager() }, null);
    SSLSocketFactory sslFactory = sslContext.getSocketFactory();

    Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("host", port));
    String auth = "Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes());

    URL url = new URL("https://www.baidu.com");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(proxy);
    conn.setRequestProperty("Proxy-Authorization", auth);
    conn.setDoInput(true);
    conn.setHostnameVerifier((v1, v2) -> true);
    conn.setSSLSocketFactory(sslFactory);
    conn.setRequestMethod("GET");
    conn.connect();
    System.out.println(conn.getResponseCode());
    System.out.println(conn.getResponseMessage());
    conn.disconnect();
}

因为这写代码并没有开源,所以无法debug,以上只能通过观察分析,在网上找了半天使用方法也没有找到,不知道有没有人知道这个要怎么使用?

回复
阅读 3.1k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏