反复出现407,不一定意味着Java发送了错误的密码。JDK参考实现通常会禁用HTTPS CONNECT隧道的Basic认证。仅提供Basic的代理可能在认证回调提供凭据之前就被拒绝。

限制凭据回调的作用范围

为Java HTTP客户端设置Authenticator,并将其限制在已配置的代理上:

String proxyHost = "203.0.113.10";
int proxyPort = 8080;
String password = System.getenv("PROXY_PASSWORD");
if (password == null) {
    throw new IllegalStateException("Set PROXY_PASSWORD");
}

java.net.Authenticator auth = new java.net.Authenticator() {
    @Override
    protected java.net.PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY
                && proxyHost.equals(getRequestingHost())
                && proxyPort == getRequestingPort()) {
            return new java.net.PasswordAuthentication(
                "proxy-user", password.toCharArray());
        }
        return null;
    }
};

java.net.http.HttpClient client = java.net.http.HttpClient.newBuilder()
    .proxy(java.net.ProxySelector.of(
        new java.net.InetSocketAddress(proxyHost, proxyPort)))
    .authenticator(auth)
    .connectTimeout(java.time.Duration.ofSeconds(5))
    .build();

这段代码用于配置单个客户端,并非设置全局默认认证器。请替换文档示例地址,使用该服务实际提供的凭据。对请求方类型和端点的检查,可避免同一个回调在应答网站认证质询时随意提供代理账号。

检查失败发生在哪个认证阶段

JDK分别为普通HTTP代理转发和CONNECT隧道设置了禁用认证方案的选项,相关名称为jdk.http.auth.proxying.disabledSchemes和jdk.http.auth.tunneling.disabledSchemes。

这解释了为什么HTTP流量能够通过认证,而经由同一个代理的HTTPS隧道却会失败。请检查运行时的conf/net.properties和部署策略,不要假定另一台机器的实际默认设置也相同。

全局清空禁用方案列表并不是通用的代理修复方法。发送给明文HTTP代理的Basic凭据,不会受到随后与目标建立的TLS连接保护。批准变更前,请审视代理传输方式、认证方法和部署策略。

JDK文档中说明的内置认证行为,也不代表它承诺支持代理声明的每一种认证方案。手动提供Authorization或Proxy-Authorization请求头会改变自动认证器的处理流程,因此当回调行为与示例不同时,请检查自定义请求头。

相关文章