Http Basic Authentication в Java с использованием HttpClient?


156

Я пытаюсь имитировать функциональность этой команды curl в Java:

curl --basic --user username:password -d "" http://ipaddress/test/login

Я написал следующее с помощью Commons HttpClient 3.0, но каким-то образом получал запрос 500 Internal Server Errorот сервера. Может кто-нибудь сказать мне, если я делаю что-то не так?

public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {

            HttpClient client = new HttpClient();

            client.getState().setCredentials(
                    new AuthScope("ipaddress", 443, "realm"),
                    new UsernamePasswordCredentials("test1", "test1")
                    );

            PostMethod post = new PostMethod(
                    "http://address/test/login");

            post.setDoAuthentication( true );

            try {
                int status = client.executeMethod( post );
                System.out.println(status + "\n" + post.getResponseBodyAsString());
            } finally {
                // release any connection resources used by the method
                post.releaseConnection();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
   } 

И позже я попробовал Commons HttpClient 4.0.1, но все та же ошибка:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;


public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        try {
            DefaultHttpClient httpclient = new DefaultHttpClient();

            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
                    new UsernamePasswordCredentials("test1", "test1"));

            HttpPost httppost = new HttpPost("http://host:post/test/login");

            System.out.println("executing request " + httppost.getRequestLine());
            HttpResponse response;
            response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            if (entity != null) {
                entity.consumeContent();
            }

            httpclient.getConnectionManager().shutdown();  
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

эм, что за ошибка появляется в логах сервера?
hvgotcodes

Ах ... У меня нет доступа к журналам сервера :(
Легенда

В большинстве случаев используемый нами ключ авторизации может быть неправильным. Проверьте dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm, чтобы увидеть, используете ли вы правильный ключ или нет. Я также запутался при выборе ключа API для Firebase. Мы должны использовать пару SENDER ID - API KEY на вкладке «Обмен сообщениями в облаке» в настройке Firebase. то есть перейдите в Firebase App -> Перейти к настройкам приложения -> Cloud Messaging, там вы можете найти ключ API Sender Id <==> и этот ключ API, который вы можете использовать для отправки FCM.
Рахул

Ответы:


187

Вы пробовали это (используя версию 4 HttpClient):

String encoding = Base64Encoder.encode(user + ":" + pwd);
HttpPost httpPost = new HttpPost("http://host:post/test/login");
httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding);

System.out.println("executing request " + httpPost.getRequestLine());
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();

64
Лучше использовать java.util.Base64с Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Майкл Берри

1
Я предпочитаю использовать javax.xml.bind.DatatypeConverter для преобразования в base64, hex и другие преобразования. Это часть JDK, поэтому нет необходимости включать дополнительные JAR.
Мубашар

1
Это версия работает для меня в моем случае использования, где HttpClient уже предоставлен, и вы не можете установить setDefaultCredentialsProvider () на сборщик при сборке httpclient. Кроме того, мне это нравится, потому что это за объем звонка. Не во всей области httpclient.
Тони

114

Итак, этот работает. На всякий случай, если кто-то захочет, вот версия, которая работает для меня :)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");
            String encoding = Base64.getEncoder().encodeToString(("test1:test1").getBytes(‌"UTF‌​-8"​));

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

}

4
Не могу найти Base64Encoder. Джонас, пожалуйста, дайте полную банку? И что такое полное имя класса Base64Encoder?
Jus12

@Amitabh: для Base64Encoderпросмотра здесь . Для Base64просмотра в commons-codec-1.6.jar в 4.2.5.zip на Apache HttpComponents Downloads , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve

22
Это не отвечает на вопрос. Вопрос касается использования HttpClient, и этот ответ не использует HttpClient.
Пол Кроаркин

9
Если вы используете Java 8, вы можете использовать java.util.Base64.
WW.

4
Вот строка для java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Джо

16

Это код из принятого ответа выше, с некоторыми изменениями, внесенными в кодировку Base64. Код ниже компилируется.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.codec.binary.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");

            Base64 b = new Base64();
            String encoding = b.encodeAsString(new String("test1:test1").getBytes());

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } 
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}

14

Небольшое обновление - надеюсь, полезно для кого-то - оно работает для меня в моем проекте:

  • Я использую класс Public Public Base64.java от Роберта Хардера (Спасибо, Роберт - код доступен здесь: Base64 - скачайте и поместите его в свой пакет).

  • и загрузите файл (изображение, документ и т. д.) с аутентификацией и запишите на локальный диск

Пример:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpBasicAuth {

public static void downloadFileWithAuth(String urlStr, String user, String pass, String outFilePath) {
    try {
        // URL url = new URL ("http://ip:port/download_url");
        URL url = new URL(urlStr);
        String authStr = user + ":" + pass;
        String authEncoded = Base64.encodeBytes(authStr.getBytes());

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setDoOutput(true);
        connection.setRequestProperty("Authorization", "Basic " + authEncoded);

        File file = new File(outFilePath);
        InputStream in = (InputStream) connection.getInputStream();
        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        for (int b; (b = in.read()) != -1;) {
            out.write(b);
        }
        out.close();
        in.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
}

2
Я получаюThe method encodeBytes(byte[]) is undefined for the type Base64
Франциско Корралес Моралес

Пользовательский класс Base64 можно заменить так, import org.apache.commons.codec.binary.Base64; как подробно описано в этом ответе на этой странице
Брэд Паркс

3
В java 8 вы можете использовать: import java.util.Base64;
WW.

7

Вот несколько моментов:

  • Вы могли бы рассмотреть возможность обновления до HttpClient 4 (вообще говоря, если вы можете, я не думаю, что версия 3 все еще активно поддерживается).

  • Код состояния 500 - это ошибка сервера, поэтому может быть полезно посмотреть, что говорит сервер (какая-либо подсказка в теле ответа, которое вы печатаете?). Хотя это может быть вызвано вашим клиентом, сервер не должен отказывать таким образом (код ошибки 4xx был бы более уместным, если запрос неверен).

  • Я думаю, что setDoAuthentication(true)это по умолчанию (не уверен). Что может быть полезно - превентивная аутентификация работает лучше:

    client.getParams().setAuthenticationPreemptive(true);

В противном случае основное отличие между curl -d ""тем, что вы делаете в Java, заключается в том, что, помимо этого Content-Length: 0, curl также отправляет Content-Type: application/x-www-form-urlencoded. Обратите внимание, что с точки зрения дизайна, вы POSTвсе равно должны отправить объект с вашим запросом.


5

Спасибо за все ответы выше, но для меня, я не могу найти класс Base64Encoder, поэтому я все равно разбираюсь.

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        String encoding = DatatypeConverter.printBase64Binary("user:passwd".getBytes("UTF-8"));
        httpGet.setHeader("Authorization", "Basic " + encoding);

        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String repsonseStr = responseString.toString();

        System.out.println("repsonseStr = " + repsonseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }

}

Еще одну вещь я тоже попробовал

Base64.encodeBase64String("user:passwd".getBytes());

Это НЕ работает из-за того, что возвращает строку почти так же с

DatatypeConverter.printBase64Binary()

но заканчивайте "\ r \ n", тогда сервер вернет "неверный запрос".

Также работает следующий код, на самом деле я сначала разбираюсь с этим, но по какой-то причине он НЕ работает в какой-то облачной среде (sae.sina.com.cn, если хотите знать, это китайский облачный сервис). поэтому необходимо использовать заголовок http вместо учетных данных HttpClient.

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();
        Client.getCredentialsProvider().setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials("user", "passwd")
        );

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String responseStr = responseString.toString();
        System.out.println("responseStr = " + responseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Base64.encodeBase64String ( "пользователь: PASSWD" .getBytes ()); работал на меня. DatatypeConverter.printBase64Binary () также работал для меня. Возможно, вы допустили ошибку в теле сообщения в предыдущем случае, и это вызвало неверный запрос. Или, может быть, это зависит от сервера.
арендует

5

при использовании массива заголовков

String auth = Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Header[] headers = {
    new BasicHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()),
    new BasicHeader("Authorization", "Basic " +auth)
};

3

для HttpClient всегда используйте HttpRequestInterceptor, например

httclient.addRequestInterceptor(new HttpRequestInterceptor() {
    public void process(HttpRequest arg0, HttpContext context) throws HttpException, IOException {
        AuthState state = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
        if (state.getAuthScheme() == null) {
            BasicScheme scheme = new BasicScheme();
            CredentialsProvider credentialsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
            Credentials credentials = credentialsProvider.getCredentials(AuthScope.ANY);
            if (credentials == null) {
                System.out.println("Credential >>" + credentials);
                throw new HttpException();
            }
            state.setAuthScope(AuthScope.ANY);
            state.setAuthScheme(scheme);
            state.setCredentials(credentials);
        }
    }
}, 0);

3

HttpBasicAuth у меня работает с небольшими изменениями

  1. Я использую Maven зависимость

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. Меньшие изменения

    String encoding = Base64.encodeBytes ((user + ":" + passwd).getBytes());

1

Простой способ для входа в систему с помощью HTTP POST , не делая каких - либо конкретных вызовов Base64 является использование HTTPClient BasicCredentialsProvider

import java.io.IOException;
import static java.lang.System.out;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;

//code
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, password);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();

HttpResponse response = client.execute(new HttpPost("http://address/test/login"));//Replace HttpPost with HttpGet if you need to perform a GET to login
int statusCode = response.getStatusLine().getStatusCode();
out.println("Response Code :"+ statusCode);

Это не работает для меня. Вызов работает, но заголовок аутентификации отсутствует.
lukas84

Странно, ваш провайдер настроен правильно?
rjdkolb

Также попробуйте обновить версию вашей библиотеки. Это сработало для меня
rjdkolb
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.