使用HttpClient在Java中进行Http基本身份验证?


156

我试图模仿Java中此curl命令的功能:

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 2010年

啊...我无权访问服务器日志:(
传奇

大多数时候,我们使用的授权密钥可能是错误的。检查dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm 以查看您是否使用了正确的密钥。在为Firebase选择API密钥时,我也感到困惑。我们必须在Firebase设置下的“云消息传递”选项卡中使用SENDER ID-API KEY对。即转到Firebase应用程序->转到应用程序设置->云消息传递,您可以在其中找到发件人ID <==> API密钥,并且可以使用此API密钥发送FCM。
拉胡尔

Answers:


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.Base64从Java 8开始更好地使用:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry

1
我更喜欢使用javax.xml.bind.DatatypeConverter转换为base64,hex等转换。它是jdk的一部分,因此无需包含任何其他JAR。
Mubashar

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 2013年

@Amitabh:在这里Base64Encoder看看。要查看Apache HttpComponents Downloads中的4.2.5.zip中的commons-codec-1.6.jar ,文档Base64import org.apache.commons.codec.binary.Base64;
Lernkurve

22
这不能回答问题。该问题询问有关使用HttpClient的问题,而此答案不使用HttpClient。
Paul Croarkin

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

一个小的更新-希望对某人有用-在我的项目中对我有用:

  • 我使用了来自Robert Harder的漂亮的Public Domain类Base64.java(感谢Robert-这里提供的代码: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
Francisco Corrales Morales 2014年

自定义Base64类可以替换为此页面上的此答案中import org.apache.commons.codec.binary.Base64; 详述的内容
Brad Parks

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还会发送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,它是中文云服务)中不起作用。因此必须使用http标头而不是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()); 为我工作。DatatypeConverter.printBase64Binary()也为我工作。可能是因为您在较早的情况下在邮件正文中犯了一个错误,从而导致了错误的请求。或者,这取决于服务器。
出租

5

在使用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

例如,对于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

另外,请尝试更新您的库的版本。这对我
有用
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.