简体   繁体   English

经过身份验证的 HTTP 代理与 Java

[英]Authenticated HTTP proxy with Java

How can I configure the username and password to authenticate a http proxy server using Java?如何配置用户名和密码以使用 Java 对 http 代理服务器进行身份验证?

I just found the following configuration parameters:我刚刚找到以下配置参数:

http.proxyHost=<proxyAddress>
http.proxyPort=<proxyPort>
https.proxyHost=<proxyAddress>
https.proxyPort=<proxyPort>

But, my proxy server requires authentication.但是,我的代理服务器需要身份验证。 How can I configure my app to use the proxy server?如何配置我的应用程序以使用代理服务器?

(EDIT: As pointed out by the OP, the using a java.net.Authenticator is required too. I'm updating my answer accordingly for the sake of correctness.) (编辑:正如 OP 所指出的,也需要使用java.net.Authenticator 。为了正确起见,我正在相应地更新我的答案。)

(EDIT#2: As pointed out in another answer , in JDK 8 it's required to remove basic auth scheme from jdk.http.auth.tunneling.disabledSchemes property) (编辑#2:正如在另一个答案中指出的,在 JDK 8 中,需要从jdk.http.auth.tunneling.disabledSchemes属性中删除basic身份验证方案)

For authentication, use java.net.Authenticator to set proxy's configuration and set the system properties http.proxyUser and http.proxyPassword .对于身份验证,使用java.net.Authenticator设置代理的配置并设置系统属性http.proxyUserhttp.proxyPassword

final String authUser = "user";
final String authPassword = "password";
Authenticator.setDefault(
  new Authenticator() {
    @Override
    public PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(authUser, authPassword.toCharArray());
    }
  }
);

System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);

System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

You're almost there, you just have to append:你快到了,你只需要附加:

-Dhttp.proxyUser=someUserName
-Dhttp.proxyPassword=somePassword

http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword says: http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword说:

Other suggest to use a custom default Authenticator.其他建议使用自定义默认身份验证器。 But that's dangerous because this would send your password to anybody who asks.但这很危险,因为这会将您的密码发送给任何询问的人。

This is relevant if some http/https requests don't go through the proxy (which is quite possible depending on configuration).如果某些 http/https 请求不通过代理(这很可能取决于配置),这是相关的。 In that case, you would send your credentials directly to some http server, not to your proxy.在这种情况下,您会将您的凭据直接发送到某个 http 服务器,而不是您的代理。

He suggests the following fix.他建议进行以下修复。

// Java ignores http.proxyUser. Here come's the workaround.
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY) {
            String prot = getRequestingProtocol().toLowerCase();
            String host = System.getProperty(prot + ".proxyHost", "");
            String port = System.getProperty(prot + ".proxyPort", "80");
            String user = System.getProperty(prot + ".proxyUser", "");
            String password = System.getProperty(prot + ".proxyPassword", "");

            if (getRequestingHost().equalsIgnoreCase(host)) {
                if (Integer.parseInt(port) == getRequestingPort()) {
                    // Seems to be OK.
                    return new PasswordAuthentication(user, password.toCharArray());  
                }
            }
        }
        return null;
    }  
});

I haven't tried it yet, but it looks good to me.我还没有尝试过,但对我来说看起来不错。

I modified the original version slightly to use equalsIgnoreCase() instead of equals(host.toLowerCase()) because of this: http://mattryall.net/blog/2009/02/the-infamous-turkish-locale-bug and I added "80" as the default value for port to avoid NumberFormatException in Integer.parseInt(port).我稍微修改了原始版本以使用 equalsIgnoreCase() 而不是 equals(host.toLowerCase()) 因为这个: http ://mattryall.net/blog/2009/02/the-inknown-turkish-locale-bug 和我添加了“80”作为端口的默认值,以避免在 Integer.parseInt(port) 中出现 NumberFormatException。

Most of the answer is in existing replies, but for me not quite.大多数答案都在现有答复中,但对我来说并不完全。 This is what works for me with java.net.HttpURLConnection (I have tested all the cases with JDK 7 and JDK 8).这就是 java.net.HttpURLConnection 对我有用的方法(我已经用 JDK 7 和 JDK 8 测试了所有情况)。 Note that you do not have to use the Authenticator class.请注意,您不必使用 Authenticator 类。

Case 1 : Proxy without user authentication, access HTTP resources案例一:代理无需用户认证,访问HTTP资源

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport

Case 2 : Proxy with user authentication, access HTTP resources案例二:代理用户认证,访问HTTP资源

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Case 3 : Proxy without user authentication, access HTTPS resources (SSL)案例三:代理无需用户认证,访问HTTPS资源(SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Case 4 : Proxy with user authentication, access HTTPS resources (SSL)案例 4:使用用户身份验证的代理,访问 HTTPS 资源 (SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Case 5 : Proxy without user authentication, access both HTTP and HTTPS resources (SSL)案例 5:代理无需用户认证,同时访问 HTTP 和 HTTPS 资源(SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Case 6 : Proxy with user authentication, access both HTTP and HTTPS resources (SSL)案例 6:具有用户身份验证的代理,同时访问 HTTP 和 HTTPS 资源 (SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttp.proxyUser=myuser -Dhttp.proxyPassword=mypass -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

You can set the properties in the with System.setProperty("key", "value) too.您也可以在 with System.setProperty("key", "value) 中设置属性。

To access HTTPS resource you may have to trust the resource by downloading the server certificate and saving it in a trust store and then using that trust store.要访问 HTTPS 资源,您可能必须通过下载服务器证书并将其保存在信任库中,然后使用该信任库来信任该资源。 ie IE

 System.setProperty("javax.net.ssl.trustStore", "c:/temp/cert-factory/my-cacerts");
 System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

For Java 1.8 and higher you must set对于 Java 1.8 及更高版本,您必须设置

-Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.tunneling.disabledSchemes=

to make proxies with Basic Authorization working with https along with Authenticator as mentioned in accepted answer如接受的答案中所述,使用基本授权与 https 以及身份验证器一起使用代理

But, setting only that parameters, the authentication don't works.但是,仅设置该参数,身份验证不起作用。

Are necessary to add to that code the following:有必要向该代码添加以下内容:

final String authUser = "myuser";
final String authPassword = "secret";

System.setProperty("http.proxyHost", "hostAddress");
System.setProperty("http.proxyPort", "portNumber");
System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);

Authenticator.setDefault(
  new Authenticator() {
    public PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(authUser, authPassword.toCharArray());
    }
  }
);

Try this runner I wrote.试试我写的这个跑步者。 It could be helpful.它可能会有所帮助。

import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;

public class ProxyAuthHelper {

    public static void main(String[] args) throws Exception {
        String tmp = System.getProperty("http.proxyUser", System.getProperty("https.proxyUser"));
        if (tmp == null) {
            System.out.println("Proxy username: ");
            tmp = new Scanner(System.in).nextLine();
        }
        final String userName = tmp;

        tmp = System.getProperty("http.proxyPassword", System.getProperty("https.proxyPassword"));
        if (tmp == null) {
            System.out.println("Proxy password: ");
            tmp = new Scanner(System.in).nextLine();
        }
        final char[] password = tmp.toCharArray();

        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                System.out.println("\n--------------\nProxy auth: " + userName);
                return new PasswordAuthentication (userName, password);
            }

         });

        Class<?> clazz = Class.forName(args[0]);
        Method method = clazz.getMethod("main", String[].class);
        String[] newArgs = new String[args.length - 1];
        System.arraycopy(args, 1, newArgs, 0, newArgs.length);
        method.invoke(null, new Object[]{newArgs});
    }

}

Since no one has mentioned this and I have seen a few examples where Authenticator.setDefault , this can cause unintentionally leaking of your username and password.由于没有人提到这一点,并且我已经看到了一些Authenticator.setDefault的示例,这可能会导致您的用户名和密码无意泄露。 Here is another way of doing this, I think this is much cleaner.这是另一种方法,我认为这更清洁。

import java.net.*;
import java.util.Base64;

class JavaFileUtil {
  private String hostname = "hostname";
  private int port = 8000;
  private String username = "username";
  private String password = "password";

  private Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, port));
  private String authHeader = new String(Base64.getEncoder().encode(new String(username + ":" + password).getBytes()));

  public void download(URL url) {
    HttpURLConnection newConnection = null;
    try {
      newConnection = (HttpURLConnection) url.openConnection(proxy);
      newConnection.setRequestProperty("Proxy-Authorization", "Basic " + authHeader);

      //The rest of your code here

    } catch (Exception e) {
      //log some error or handle it
    } finally {
      //Make sure you close the connection
      if (newConnection != null) newConnection.disconnect();
    }
  }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM