okHttp 3.x аутентификатор не вызывается - PullRequest
1 голос
/ 24 апреля 2019

Мне нужно сделать запрос через прокси, который нуждается в аутентификации.

    public class WebClient {

    private final OkHttpClient httpClient;
    private static WebClient webClient;

    private WebClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        if (Configurator.getInstance().useProxy()) {
            builder.proxySelector(new CustomProxySelector());
            builder.authenticator((Route route, Response response) -> {
                String credential = Credentials.basic("MYUSER", "MYPSW");
                return response.request().newBuilder().header("Authorization", credential).build();
            });
        } else
            builder.proxy(Proxy.NO_PROXY);

        httpClient = builder
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();
    }
}

Но с помощью отладчика я вижу, что метод аутентификатора никогда не вызывается, и я получаю 407 в качестве ответа на любой запрос.

Однако, когда я использую HttpURLConnection с Authenticator.setDefault, онработает просто отлично, и я могу использовать свою аутентификацию по доверенности:

public boolean hasInternetConnection() throws IOException {
    Request httpRequest = new Request.Builder().url("http://www.google.com/").build();
    // This fails with 407
    Response httpResponse = httpClient.newCall(httpRequest).execute();

    java.net.Authenticator authenticator = new java.net.Authenticator() {
        public PasswordAuthentication getPasswordAuthentication() {
            return (new PasswordAuthentication("MYUSER", "MYPSW".toCharArray()));
        }
    };

    java.net.Authenticator.setDefault(authenticator);

    URL obj = new URL("http://www.google.com/");
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    con.setRequestMethod("GET");
    // This works with 200
    int responseCode = con.getResponseCode();

    return false;
}

Поэтому я думаю, что вопрос в том, почему метод OkHttpClient.Builder.authenticator не вызывается?

1 Ответ

1 голос
/ 30 апреля 2019

Как указал Гимби, одной из проблем было то, что я вызывал неправильный метод. Меня смутило то, что иногда proxyAuthenticator не вызывали, и я пытался понять, почему.

Приложение, которое я разрабатываю, должно иметь доступ к ресурсам внутри и вне моей рабочей сети. Поэтому, когда мне нужен внешний доступ, я должен использовать прокси-сервер с аутентификацией. Это работает так:

  1. Сделан запрос к интернет-хосту;
  2. ProxySelector решает, что HTTP-клиент должен использовать прокси для этого запрос, так как это интернет-хостинг;
  3. Поскольку прокси установлен, ProxyAuthenticator вызывается для отправки заголовок авторизации в запросе .

Однако, когда делается запрос к внутреннему хосту , ProxySelector решает, что нет необходимости использовать прокси. Следовательно, ProxyAuthenticator не вызывается, так как нет активного прокси.

Вот моя реализация для всех, кому интересно:

WebClient.java

    public class WebClient {

    private final OkHttpClient httpClient;
    private static WebClient webClient;

    private WebClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        if (Configurator.getInstance().useProxy()) {
            CodeUtils.setProxy();
            builder.proxySelector(new CustomProxySelector());
            builder.proxyAuthenticator(new CustomProxyAuthenticator());
        } else {
            builder.proxy(Proxy.NO_PROXY);
            CodeUtils.removeProxy();
        }

        httpClient = builder
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();
    }

    public static WebClient getInstance() {
        return webClient != null ? webClient : (webClient = new WebClient());
    }

    public static void reload() {
        webClient = null;
    }

    public String doGet(String url) throws IOException {
        Request httpRequest = new Request.Builder().url(url).build();
        Response httpResponse = httpClient.newCall(httpRequest).execute();

        if (httpResponse.code() != 200) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("success", false);
            jsonObject.put("msg", httpResponse.body().string());
            jsonObject.put("httpCode", httpResponse.code());
            return jsonObject.toString();
        }

        return httpResponse.body().string();
    }

    public String doPost(String url, JSONObject body) throws IOException {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body.toString());
        Request request = new Request.Builder()
                .header("Accept", "application/json")
                .header("Content-type", "application/json; charset=UTF-8")
                .url(url)
                .post(requestBody).build();
        Response response = httpClient.newCall(request).execute();
        return response.body().string();
    }
}

CustomProxyAuthenticator.java

public class CustomProxyAuthenticator implements Authenticator {

    @Override
    public Request authenticate(Route route, Response response) throws IOException {
        String username = Configurator.getInstance().getProxyUser();
        String password = Configurator.getInstance().getProxyPassword();

        String credential = Credentials.basic(username, password);
        return response.request().newBuilder()
                .header("Proxy-Authorization", credential)
                .build();
    }
}

CustomProxySelector.java

public class CustomProxySelector extends ProxySelector {

    private Configurator configurator = Configurator.getInstance();
    private List<String> nonProxyHosts = Arrays.asList(configurator.getNonProxyHosts().split("\\|"));
    private String proxyHost = configurator.getProxyHost();
    private int proxyPort = configurator.getProxyPort();

    @Override
    public List<Proxy> select(URI uri) {
        final List<Proxy> proxyList = new ArrayList<>(1);
        String host = uri.getHost();

        if (host.startsWith("127.0.0.1") || nonProxyHosts.contains(host))
            proxyList.add(Proxy.NO_PROXY);
        else
            proxyList.add(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)));

        return proxyList;
    }

    @Override
    public void connectFailed(URI arg0, SocketAddress arg1, IOException arg2) {
    }
}
...