Otentikasi Dasar Http di Java menggunakan HttpClient?

156

Saya mencoba untuk meniru fungsionalitas dari perintah curl ini di Java:

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

Saya menulis yang berikut menggunakan Commons HttpClient 3.0 tetapi entah bagaimana akhirnya mendapatkan 500 Internal Server Errordari server. Dapatkah seseorang memberi tahu saya jika saya melakukan sesuatu yang salah?

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

Dan saya kemudian mencoba Commons HttpClient 4.0.1 tetapi masih kesalahan yang sama:

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();
        }
}
Legenda
sumber
um, apa kesalahan yang muncul di log server?
hvgotcodes
Ah ... Saya tidak punya akses ke log server :(
Legenda
Sebagian besar waktu kunci Otorisasi yang kami gunakan bisa salah. Periksa dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm untuk melihat Anda menggunakan kunci yang benar atau tidak. Saya juga bingung ketika memilih kunci API untuk firebase. Kita harus menggunakan pasangan SENDER - API KEY pair di tab perpesanan cloud di bawah pengaturan firebase. yaitu Buka Aplikasi firebase -> Buka pengaturan aplikasi -> Cloud Messaging di sana Anda dapat menemukan Id Pengirim <==> kunci API dan kunci API ini yang dapat Anda gunakan untuk mengirim FCM.
Rahul

Jawaban:

187

Sudahkah Anda mencoba ini (menggunakan HttpClient versi 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();
Buhake Sindi
sumber
64
Lebih baik menggunakan java.util.Base64Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry
1
Saya lebih suka menggunakan javax.xml.bind.DatatypeConverter untuk mengkonversi dari ke base64, hex dan konversi lainnya. itu bagian dari jdk jadi tidak perlu menyertakan JAR tambahan.
Mubashar
1
Ini adalah versi yang berfungsi untuk saya dalam kasus penggunaan saya di mana HttpClient sudah disediakan dan Anda tidak dapat mengatur setDefaultCredentialsProvider () pada pembangun saat membangun httpclient. Saya juga suka karena itu per lingkup panggilan. Tidak di seluruh lingkup httpclient.
Tony
114

Ok jadi yang ini berfungsi. Kalau-kalau ada yang menginginkannya, inilah versi yang bekerja untuk saya :)

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

    }

}
Legenda
sumber
4
Tidak dapat menemukan Base64Encoder. Jonas, bisakah kamu berikan kendi penuhnya? Juga apa nama kelas yang sepenuhnya memenuhi syarat Base64Encoder?
Jus12
@Amitabh: Untuk Base64Encodermelihat di sini . Untuk Base64melihat di commons-codec-1.6.jar di 4.2.5.zip di Apache HttpComponents Downloads , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve
22
Ini tidak menjawab pertanyaan. Pertanyaannya adalah tentang menggunakan HttpClient dan jawaban ini tidak menggunakan HttpClient.
Paul Croarkin
9
Jika Anda menggunakan Java 8, Anda dapat menggunakan java.util.Base64.
WW.
4
Inilah baris untuk java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe
16

Ini adalah kode dari jawaban yang diterima di atas, dengan beberapa perubahan yang dilakukan terkait pengkodean Base64. Kode di bawah ini mengkompilasi.

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

Pembaruan kecil - semoga bermanfaat bagi seseorang - ini berfungsi untuk saya di proyek saya:

  • Saya menggunakan kelas Public Domain bagus Base64.java dari Robert Harder (Terima kasih Robert - Kode tersedia di sini: Base64 - unduh dan masukkan ke dalam paket Anda).

  • dan unduh file (gambar, dok, dll.) dengan autentikasi dan tulis ke disk lokal

Contoh:

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();
    }
}
}
Ralph At skillyard
sumber
2
Saya dapatkanThe method encodeBytes(byte[]) is undefined for the type Base64
Francisco Corrales Morales
Kebiasaan kelas Base64 bisa diganti dengan import org.apache.commons.codec.binary.Base64; yang rinci dalam jawaban ini di halaman ini
Brad Taman
3
Di java 8, Anda dapat menggunakan: import java.util.Base64;
WW.
7

Inilah beberapa poin:

  • Anda dapat mempertimbangkan untuk meningkatkan ke HttpClient 4 (secara umum, jika Anda bisa, saya rasa versi 3 masih tidak didukung secara aktif).

  • Kode status 500 adalah kesalahan server, jadi mungkin berguna untuk melihat apa yang dikatakan server (ada petunjuk di badan respons yang Anda cetak?). Meskipun mungkin disebabkan oleh klien Anda, server tidak boleh gagal dengan cara ini (kode kesalahan 4xx akan lebih sesuai jika permintaan salah).

  • Saya pikir setDoAuthentication(true)adalah default (tidak yakin). Apa yang bisa berguna untuk dicoba adalah otentikasi pre-emptive berfungsi lebih baik:

    client.getParams().setAuthenticationPreemptive(true);

Kalau tidak, perbedaan utama antara curl -d ""dan apa yang Anda lakukan di Jawa adalah bahwa, di samping Content-Length: 0, curl juga mengirim Content-Type: application/x-www-form-urlencoded. Perhatikan bahwa dalam hal desain, Anda mungkin harus mengirim entitas dengan POSTpermintaan Anda .

Bruno
sumber
5

Terima kasih atas semua jawaban di atas, tetapi untuk saya, saya tidak dapat menemukan kelas Base64Encoder, jadi saya tetap memilah jalan saya.

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

}

Satu hal lagi, saya juga mencoba

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

Ini TIDAK berfungsi karena mengembalikan string yang hampir sama dengan

DatatypeConverter.printBase64Binary()

tetapi diakhiri dengan "\ r \ n", maka server akan mengembalikan "permintaan buruk".

Kode berikut juga berfungsi, sebenarnya saya memilah ini terlebih dahulu, tetapi untuk beberapa alasan, ini TIDAK bekerja di beberapa lingkungan cloud (sae.sina.com.cn jika Anda ingin tahu, ini adalah layanan cloud Cina). jadi harus menggunakan header http bukan kredensial 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();
    }
}
chenyi1976
sumber
Base64.encodeBase64String ("user: passwd" .getBytes ()); bekerja untukku. DatatypeConverter.printBase64Binary () juga bekerja untuk saya. Bisa jadi Anda membuat kesalahan di badan pesan dalam kasus sebelumnya dan itu menyebabkan permintaan yang buruk. Atau mungkin itu tergantung pada server.
sewa
5

saat menggunakan Header array

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

untuk HttpClient selalu gunakan HttpRequestInterceptor misalnya

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);
EngrSofty
sumber
3

HttpBasicAuth berfungsi untuk saya dengan perubahan yang lebih kecil

  1. Saya menggunakan ketergantungan pakar

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. Perubahan kecil

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

Cara mudah untuk login dengan POST HTTP tanpa melakukan panggilan khusus Base64 adalah dengan menggunakan 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);
rjdkolb
sumber
Ini tidak bekerja untuk saya. Panggilan berfungsi tetapi tidak ada tajuk otentikasi.
lukas84
Aneh, apakah provider Anda diatur dengan benar?
rjdkolb
Coba juga perbarui versi perpustakaan Anda. Ini bekerja untuk saya
rjdkolb