Основна автентифікація Http на 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 - API KEY на вкладці хмарних повідомлень під налаштуванням firebase. тобто перейдіть до програми Firebase -> Перейдіть до налаштування програми -> Cloud Messaging, там ви можете знайти Sender Id <==> ключ API та цей ключ API, який ви можете використовувати для надсилання FCM.
Рахул

Відповіді:


187

Ви спробували це (використовуючи HttpClient версії 4):

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?
липня 1313

@Amitabh: Base64EncoderПодивіться тут . Для Base64дивитися в Вікісховища кодек-1.6.jar в 4.2.5.zip в Apache HttpComponents Завантаженні , док ,import org.apache.commons.codec.binary.Base64;
Lernkurve

22
Це не дає відповіді на запитання. Питання задає питання про використання HttpClient, і ця відповідь не використовує HttpClient.
Пол Кроаркін

9
Якщо ви використовуєте Java 8, ви можете використовувати java.util.Base64.
ВВ.

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 Domain 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; таким, який детально описаний у цій відповіді на цій сторінці
Brad Parks

3
У java 8 ви можете використовувати: import java.util.Base64;
ВВ.

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.