Authentification de base Http en Java à l'aide de HttpClient?


156

J'essaie d'imiter la fonctionnalité de cette commande curl en Java:

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

J'ai écrit ce qui suit en utilisant Commons HttpClient 3.0 mais j'ai fini par obtenir un message 500 Internal Server Errordu serveur. Quelqu'un peut-il me dire si je fais quelque chose de mal?

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

Et j'ai essayé plus tard un Commons HttpClient 4.0.1 mais toujours la même erreur:

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

euh, quelle est l'erreur apparaissant dans les journaux du serveur?
hvgotcodes

Ah ... je n'ai pas accès aux logs du serveur :(
Légende

La plupart du temps, la clé d'autorisation que nous utilisons peut être erronée. Vérifiez dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm pour voir que vous utilisez la bonne clé ou non. J'ai également été confus lors de la sélection de la clé API pour Firebase.Nous devons utiliser la paire SENDER ID - API KEY dans l'onglet de messagerie Cloud sous le paramètre Firebase. c'est-à-dire Accédez à l'application Firebase -> Accédez aux paramètres de l'application -> Cloud Messaging, vous pouvez y trouver la clé API de l'ID de l'expéditeur <==> et cette clé API que vous pouvez utiliser pour envoyer FCM.
Rahul

Réponses:


187

Avez-vous essayé ceci (en utilisant 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
Mieux vaut utiliser à java.util.Base64partir de Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry

1
Je préfère utiliser javax.xml.bind.DatatypeConverter pour convertir en base64, hexadécimal et autre conversion. il fait partie de jdk donc pas besoin d'inclure de JAR supplémentaire.
Mubashar

1
C'est la version qui fonctionne pour moi dans mon cas d'utilisation où le HttpClient est déjà fourni et vous ne pouvez pas définir le setDefaultCredentialsProvider () sur le générateur lors de la génération du client http. Aussi je l'aime parce que c'est par portée d'appel. Pas sur l'ensemble du périmètre httpclient.
Tony

114

Ok donc celui-ci fonctionne. Juste au cas où quelqu'un le voudrait, voici la version qui fonctionne pour moi :)

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
Impossible de trouver Base64Encoder. Jonas pouvez-vous s'il vous plaît donner le pot plein? Quel est également le nom complet de la classe Base64Encoder?
Jus12

@Amitabh: Pour Base64Encoderregarder ici . Pour Base64regarder dans commons-codec-1.6.jar dans 4.2.5.zip sur Apache HttpComponents Downloads , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve

22
Cela ne répond pas à la question. La question concerne l'utilisation de HttpClient et cette réponse n'utilise pas HttpClient.
Paul Croarkin

9
Si vous utilisez Java 8, vous pouvez utiliser java.util.Base64.
WW.

4
Voici la ligne pour java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe

16

C'est le code de la réponse acceptée ci-dessus, avec quelques modifications apportées concernant l'encodage Base64. Le code ci-dessous se compile.

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

Une petite mise à jour - j'espère utile pour quelqu'un - cela fonctionne pour moi dans mon projet:

  • J'utilise la belle classe de domaine public Base64.java de Robert Harder (Merci Robert - Code disponible ici: Base64 - téléchargez-le et mettez-le dans votre paquet).

  • et faire un téléchargement d'un fichier (image, doc, etc.) avec authentification et écrire sur le disque local

Exemple:

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

La classe Base64 personnalisée peut être remplacée par import org.apache.commons.codec.binary.Base64; comme détaillé dans cette réponse sur cette page
Brad Parks

3
Dans java 8, vous pouvez utiliser: import java.util.Base64;
WW.

7

Voici quelques points:

  • Vous pouvez envisager de passer à HttpClient 4 (de manière générale, si vous le pouvez, je ne pense pas que la version 3 soit toujours activement prise en charge).

  • Un code d'état 500 est une erreur de serveur, il peut donc être utile de voir ce que dit le serveur (un indice dans le corps de la réponse que vous imprimez?). Bien que cela puisse être causé par votre client, le serveur ne devrait pas échouer de cette façon (un code d'erreur 4xx serait plus approprié si la demande est incorrecte).

  • Je pense que setDoAuthentication(true)c'est la valeur par défaut (pas sûr). Ce qui pourrait être utile à essayer, c'est que l'authentification préemptive fonctionne mieux:

    client.getParams().setAuthenticationPreemptive(true);

Sinon, la principale différence entre curl -d ""et ce que vous faites en Java est que, en plus de Content-Length: 0, curl envoie également Content-Type: application/x-www-form-urlencoded. Notez qu'en termes de design, vous devriez probablement envoyer une entité avec votre POSTdemande de toute façon.


5

Merci pour toutes les réponses ci-dessus, mais pour moi, je ne trouve pas la classe Base64Encoder, donc je me débrouille quand même.

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

}

Encore une chose, j'ai aussi essayé

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

Cela ne fonctionne PAS car il renvoie une chaîne presque identique avec

DatatypeConverter.printBase64Binary()

mais finissez par "\ r \ n", alors le serveur retournera "mauvaise demande".

Le code suivant fonctionne également, en fait, je règle ce problème en premier, mais pour une raison quelconque, il ne fonctionne PAS dans certains environnements cloud (sae.sina.com.cn si vous voulez savoir, c'est un service cloud chinois). il faut donc utiliser l'en-tête http au lieu des informations d'identification 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 ("utilisateur: passwd" .getBytes ()); travaillé pour moi. DatatypeConverter.printBase64Binary () a également fonctionné pour moi. Il se peut que vous ayez fait une erreur dans le corps du message dans le cas précédent et que cela ait provoqué une mauvaise demande. Ou peut-être que cela dépend du serveur.
loue le

5

lors de l'utilisation du tableau d'en-tête

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

pour HttpClient, utilisez toujours HttpRequestInterceptor par exemple

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 fonctionne pour moi avec des modifications plus petites

  1. J'utilise la dépendance maven

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. Petit changement

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

1

Un moyen simple de se connecter avec un HTTP POST sans effectuer d'appels spécifiques à Base64 consiste à utiliser 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);

Cela ne fonctionne pas pour moi. L'appel fonctionne mais aucun en-tête d'authentification n'est présent.
lukas84

Étrange, votre fournisseur est-il correctement configuré?
rjdkolb

Essayez également de mettre à jour la version de votre bibliothèque. Cela a fonctionné pour moi
rjdkolb
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.