HTTP-Basisauthentifizierung in Java mit HttpClient?


156

Ich versuche, die Funktionalität dieses Curl-Befehls in Java nachzuahmen:

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

Ich habe das Folgende mit Commons HttpClient 3.0 geschrieben, aber irgendwie bekam ich eine 500 Internal Server Errorvom Server. Kann mir jemand sagen, ob ich etwas falsch mache?

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();
        }
    }
   } 

Und ich habe später einen Commons HttpClient 4.0.1 ausprobiert, aber immer noch den gleichen Fehler:

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();
        }
}

ähm, was ist der Fehler, der in den Serverprotokollen angezeigt wird?
Hvgotcodes

Ah ... Ich habe keinen Zugriff auf die Serverprotokolle :(
Legende

In den meisten Fällen kann der von uns verwendete Autorisierungsschlüssel falsch sein. Überprüfen Sie dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm , um festzustellen , ob Sie den richtigen Schlüssel verwenden oder nicht. Ich war auch verwirrt, als ich den API-Schlüssel für die Firebase auswählte. Wir müssen das Paar SENDER ID - API KEY auf der Registerkarte Cloud-Messaging unter der Firebase-Einstellung verwenden. dh Gehen Sie zur Firebase-App -> Gehen Sie zur App-Einstellung -> Cloud Messaging. Dort finden Sie den Absender-ID <==> API-Schlüssel und diesen API-Schlüssel, mit dem Sie FCM senden können.
Rahul

Antworten:


187

Haben Sie dies versucht (mit HttpClient Version 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
Besser java.util.Base64ab Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry

1
Ich bevorzuge die Verwendung von javax.xml.bind.DatatypeConverter, um von base64, hex und anderen Konvertierungen zu konvertieren. Es ist Teil von JDK, sodass keine zusätzliche JAR erforderlich ist.
Mubashar

1
Dies ist die Version, die für mich in meinem Anwendungsfall funktioniert, in dem der HttpClient bereits bereitgestellt ist und Sie den setDefaultCredentialsProvider () nicht im Builder festlegen können, während Sie den httpclient erstellen. Ich mag es auch, weil es pro Anrufumfang ist. Nicht im gesamten httpclient-Bereich.
Tony

114

Ok, das funktioniert. Nur für den Fall, dass jemand es will, hier ist die Version, die für mich funktioniert :)

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
Kann nicht finden Base64Encoder. Jonas, kannst du bitte das volle Glas geben? Wie lautet auch der vollqualifizierte Klassenname Base64Encoder?
Jus12

@Amitabh: Für Base64EncoderLook hier . Für den Base64Blick in commons-codec-1.6.jar in 4.2.5.zip bei Apache HttpComponents Downloads , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve

22
Dies beantwortet die Frage nicht. In der Frage wird nach der Verwendung von HttpClient gefragt, und in dieser Antwort wird HttpClient nicht verwendet.
Paul Croarkin

9
Wenn Sie Java 8 verwenden, können Sie java.util.Base64 verwenden.
WW.

4
Hier ist die Zeile für java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe

16

Dies ist der Code aus der oben akzeptierten Antwort, wobei einige Änderungen in Bezug auf die Base64-Codierung vorgenommen wurden. Der folgende Code wird kompiliert.

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

Ein kleines Update - hoffentlich nützlich für jemanden - es funktioniert für mich in meinem Projekt:

  • Ich verwende die nette Public Domain-Klasse Base64.java von Robert Harder (Danke Robert - Code hier verfügbar: Base64 - herunterladen und in Ihr Paket einfügen ).

  • und laden Sie eine Datei (Bild, Dokument usw.) mit Authentifizierung herunter und schreiben Sie auf die lokale Festplatte

Beispiel:

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
Ich bekommeThe method encodeBytes(byte[]) is undefined for the type Base64
Francisco Corrales Morales

Die benutzerdefinierte Base64-Klasse kann import org.apache.commons.codec.binary.Base64; wie in dieser Antwort auf dieser Seite beschrieben ersetzt werden
Brad Parks

3
In Java 8 können Sie Folgendes verwenden: import java.util.Base64;
WW.

7

Hier sind einige Punkte:

  • Sie könnten ein Upgrade auf HttpClient 4 in Betracht ziehen (im Allgemeinen, wenn Sie können, glaube ich nicht, dass Version 3 noch aktiv unterstützt wird).

  • Ein 500-Statuscode ist ein Serverfehler. Daher kann es hilfreich sein, zu sehen, was der Server sagt (Hinweise im Antworttext, den Sie drucken?). Obwohl dies möglicherweise von Ihrem Client verursacht wird, sollte der Server auf diese Weise nicht ausfallen (ein 4xx-Fehlercode wäre besser geeignet, wenn die Anforderung falsch ist).

  • Ich denke, setDoAuthentication(true)ist die Standardeinstellung (nicht sicher). Es könnte nützlich sein, zu versuchen, dass die vorbeugende Authentifizierung besser funktioniert:

    client.getParams().setAuthenticationPreemptive(true);

Ansonsten besteht der Hauptunterschied zwischen curl -d ""und dem, was Sie in Java tun, darin Content-Length: 0, dass Curl zusätzlich auch sendet Content-Type: application/x-www-form-urlencoded. Beachten Sie, dass Sie in Bezug auf das Design wahrscheinlich POSTtrotzdem eine Entität mit Ihrer Anfrage senden sollten .


5

Vielen Dank für alle Antworten oben, aber für mich kann ich die Base64Encoder-Klasse nicht finden, also sortiere ich meinen Weg trotzdem.

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();
    }

}

Eine weitere Sache habe ich auch versucht

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

Es funktioniert NICHT, da es einen String zurückgibt, mit dem es fast identisch ist

DatatypeConverter.printBase64Binary()

aber beenden Sie mit "\ r \ n", dann gibt der Server "schlechte Anfrage" zurück.

Auch der folgende Code funktioniert, eigentlich sortiere ich das zuerst aus, aber aus irgendeinem Grund funktioniert er NICHT in einer Cloud-Umgebung (sae.sina.com.cn, wenn Sie wissen möchten, dass es sich um einen chinesischen Cloud-Dienst handelt). Sie müssen daher den http-Header anstelle der HttpClient-Anmeldeinformationen verwenden.

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 ("user: passwd" .getBytes ()); arbeitete für mich. DatatypeConverter.printBase64Binary () hat auch bei mir funktioniert. Es kann sein, dass Sie in einem früheren Fall einen Fehler im Nachrichtentext gemacht haben und dies zu einer schlechten Anfrage geführt hat. Oder vielleicht hängt es vom Server ab.
Mieten

5

während der Verwendung des Header-Arrays

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

Verwenden Sie für HttpClient beispielsweise immer 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 funktioniert bei mir mit kleineren Änderungen

  1. Ich benutze Maven-Abhängigkeit

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. Kleinere Änderung

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

1

Ein einfacher Weg , sich mit einem HTTP-POST anzumelden, ohne Base64-spezifische Aufrufe auszuführen, ist die Verwendung des 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);

Das funktioniert bei mir nicht. Der Aufruf funktioniert, aber es ist kein Authentifizierungsheader vorhanden.
lukas84

Seltsam, ist Ihr Provider richtig eingestellt?
rjdkolb

Versuchen Sie auch, die Version Ihrer Bibliothek zu aktualisieren. Dies funktionierte für mich
rjdkolb
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.