Autenticazione di base HTTP in Java utilizzando HttpClient?


156

Sto cercando di imitare la funzionalità di questo comando curl in Java:

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

Ho scritto quanto segue usando Commons HttpClient 3.0, ma in qualche modo ho finito per ottenere un 500 Internal Server Errordal server. Qualcuno può dirmi se sto facendo qualcosa di sbagliato?

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

E più tardi ho provato un Commons HttpClient 4.0.1 ma ancora lo stesso errore:

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

um, qual è l'errore che appare nei registri del server?
hvgotcodes

Ah ... Non ho accesso ai registri del server :(
Legenda

Il più delle volte la chiave di autorizzazione che stiamo usando potrebbe essere sbagliata. Controlla dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm per vedere se stai usando la chiave corretta oppure no. Mi sono anche confuso durante la selezione della chiave API per firebase Dobbiamo utilizzare ID SENDER - coppia API KEY nella scheda Messaggi cloud sotto l'impostazione firebase. ad es. Vai all'app Firebase -> Vai alle impostazioni dell'app -> Messaggi cloud lì puoi trovare l'ID mittente <==> chiave API e questa chiave API che puoi usare per inviare FCM.
Rahul,

Risposte:


187

Hai provato questo (usando HttpClient versione 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
Meglio usare java.util.Base64come da Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry

1
Preferisco usare javax.xml.bind.DatatypeConverter per convertire da base64, hex e altre conversioni. fa parte di jdk, quindi non è necessario includere alcun JAR aggiuntivo.
Mubashar,

1
Questa è la versione che funziona per me nel mio caso d'uso in cui HttpClient è già fornito e non è possibile impostare setDefaultCredentialsProvider () sul builder durante la creazione di httpclient. Inoltre mi piace perché è per portata di chiamata. Non sull'intero ambito httpclient.
Tony,

114

Ok, questo funziona. Nel caso in cui qualcuno lo voglia, ecco la versione che funziona per me :)

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
Non riesci a trovare Base64Encoder. Jonas puoi per favore dare il barattolo pieno? Qual è anche il nome completo della classe di Base64Encoder?
Jus12,

@Amitabh: per Base64Encoderguardare qui . Per Base64un'occhiata in commons-codec-1.6.jar in 4.2.5.zip in Download di Apache HttpComponents , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve,

22
Questo non risponde alla domanda. La domanda è sull'uso di HttpClient e questa risposta non utilizza HttpClient.
Paul Croarkin,

9
Se si utilizza Java 8, è possibile utilizzare java.util.Base64.
WW.

4
Ecco la linea per java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe

16

Questo è il codice dalla risposta accettata sopra, con alcune modifiche apportate alla codifica Base64. Il codice seguente viene compilato.

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

Un piccolo aggiornamento - si spera utile per qualcuno - funziona per me nel mio progetto:

  • Uso la simpatica classe Public64 Base64.java di Robert Harder (Grazie Robert - Codice disponibile qui: Base64 - Scarica e metti nel tuo pacchetto).

  • e fare un download di un file (immagine, doc, ecc.) con autenticazione e scrivere sul disco locale

Esempio:

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

La classe Base64 personalizzata può essere sostituita con import org.apache.commons.codec.binary.Base64; quanto dettagliato in questa risposta in questa pagina
Brad Parks

3
In java 8 è possibile utilizzare: import java.util.Base64;
WW.

7

Ecco alcuni punti:

  • Potresti prendere in considerazione l'aggiornamento a HttpClient 4 (in generale, se puoi, non credo che la versione 3 sia ancora supportata attivamente).

  • Un codice di stato 500 è un errore del server, quindi potrebbe essere utile vedere cosa dice il server (qualche indizio nel corpo della risposta che stai stampando?). Anche se potrebbe essere causato dal tuo client, il server non dovrebbe fallire in questo modo (un codice di errore 4xx sarebbe più appropriato se la richiesta non è corretta).

  • Penso che setDoAuthentication(true)sia l'impostazione predefinita (non sono sicuro). Ciò che potrebbe essere utile provare è che l'autenticazione preventiva funziona meglio:

    client.getParams().setAuthenticationPreemptive(true);

Altrimenti, la differenza principale tra curl -d ""e quello che stai facendo in Java è che, oltre a Content-Length: 0, arriccia anche Content-Type: application/x-www-form-urlencoded. Nota che in termini di design, dovresti comunque inviare un'entità con la tua POSTrichiesta.


5

Grazie per tutte le risposte sopra, ma per me non riesco a trovare la classe Base64Encoder, quindi mi occupo comunque della mia strada.

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

}

Un'altra cosa, ho anche provato

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

NON funziona perché restituisce una stringa quasi uguale a

DatatypeConverter.printBase64Binary()

ma termina con "\ r \ n", quindi il server restituirà "richiesta errata".

Anche il seguente codice funziona, in realtà lo risolvo prima, ma per qualche motivo, NON funziona in un ambiente cloud (sae.sina.com.cn se vuoi sapere, è un servizio cloud cinese). quindi devi usare l'intestazione http invece delle credenziali 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 ( "user: passwd" .getBytes ()); ha funzionato per me. Anche DatatypeConverter.printBase64Binary () ha funzionato per me. È possibile che tu abbia commesso un errore nel corpo del messaggio nel caso precedente e che abbia causato una richiesta errata. O forse dipende dal server.
affitta il

5

durante l'utilizzo dell'array Header

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

per HttpClient usare sempre HttpRequestInterceptor per esempio

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 funziona per me con modifiche minori

  1. Uso la dipendenza maven

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. Piccolo cambiamento

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

1

Un modo semplice per accedere con un POST HTTP senza effettuare chiamate specifiche Base64 è utilizzare 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);

Questo non funziona per me. La chiamata funziona ma non è presente alcuna intestazione di autenticazione.
lukas84,

Strano, il tuo provider è impostato correttamente?
rjdkolb,

Prova anche ad aggiornare la versione della tua libreria. Questo ha funzionato per me
rjdkolb il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.