HttpClientを使用したJavaでのHttp基本認証?


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 '19

ああ...サーバーログにアクセスできません:(
Legend

ほとんどの場合、使用している認証キーは間違っている可能性があります。dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm をチェックして、正しいキーを使用しているかどうかを確認します。また、firebaseのAPIキーを選択するときに混乱しました。firebase設定の下の[クラウドメッセージング]タブで、SENDER ID-API KEYペアを使用する必要があります。つまり、firebaseアプリに移動します->アプリ設定に移動します->クラウドメッセージングでは、送信者ID <==> APIキーと、FCMの送信に使用できるこのAPIキーを見つけることができます。
Rahul

回答:


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.Base64Java 8以降で使用する方がよい:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry、

1
私はjavax.xml.bind.DatatypeConverterを使用してbase64、16進数、その他の変換に変換することを好みます。これはjdkの一部であるため、追加のJARを含める必要はありません。
Mubashar 2018年

1
これは、HttpClientがすでに提供されており、httpclientのビルド中にビルダーでsetDefaultCredentialsProvider()を設定できない場合に使用できるバージョンです。また、コールスコープごとなので、気に入っています。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どうですか?
Jus12

@Amitabh:ここをBase64Encoder見てください。以下のためBase64の4.2.5.zip中コモンズ・コーデック-1.6.jarで見アパッチHttpComponentsダウンロードドキュメントimport org.apache.commons.codec.binary.Base64;
Lernkurve

22
これは質問の答えにはなりません。質問はHttpClientの使用について尋ね、この回答はHttpClientを使用しません。
Paul Croarkin 2013年

9
Java 8を使用している場合は、java.util.Base64を使用できます。
WW。

4
これがjava.util.Base64の行ですString encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe

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

小さな更新-誰かのために役立つと思います-それは私のプロジェクトで私のために働きます:

  • 私はロバート・ハーダーから素敵なパブリックドメインクラスBase64.javaを使う( -コードのavailbleここに感謝ロバート: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
フランシスコ・コラレス・モラレス2014年

カスタムBase64クラスは、このページのこの回答で詳しく説明されimport org.apache.commons.codec.binary.Base64; いるように置き換えることができます
Brad Parks 14

3
Java 8では、次を使用できます。import java.util.Base64;
WW。

7

ここにいくつかのポイントがあります:

  • HttpClient 4へのアップグレードを検討することもできます(一般的に言えば、可能であれば、バージョン3がまだ積極的にサポートされているとは思いません)。

  • 500ステータスコードはサーバーエラーであるため、サーバーの発言(印刷している応答本文の手がかり)を確認すると役立つ場合があります。これはクライアントが原因である可能性がありますが、サーバーはこのように失敗しないはずです(要求が正しくない場合は、4xxエラーコードの方が適切です)。

  • setDoAuthentication(true)デフォルトだと思います(わかりません)。試してみると便利なのは、プリエンプティブ認証がうまく機能することです。

    client.getParams().setAuthenticationPreemptive(true);

それ以外の場合と、curl -d ""Javaで行っていることの主な違いはContent-Length: 0、curl に加えて、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、中国のクラウドサービスです)。したがって、HttpClient資格情報の代わりにhttpヘッダーを使用する必要があります。

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()); 私のために働いた。DatatypeConverter.printBase64Binary()も私のために働いた。以前のケースでメッセージ本文に誤りを犯し、それが不正な要求を引き起こした可能性があります。または、それはサーバーに依存します。
2016

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

Base64固有の呼び出しを行わずに HTTP POSTでログインする簡単な方法は、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.