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

我试图在 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();
}
}
535984 次浏览

好的,这个版本可以用。如果有人想要的话,这个版本对我很有用:)

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


}


}

以下是一些要点:

  • 您可以考虑升级到 HttpClient4(一般来说,如果可以的话,我认为版本3不会得到积极支持)。

  • 500状态代码是一个服务器错误,因此查看服务器发出的信息可能很有用(您正在打印的响应主体中有什么线索吗?).尽管这可能是由客户机引起的,但服务器不应该以这种方式失败(如果请求不正确,则使用4xx 错误代码更合适)。

  • 我认为 setDoAuthentication(true)是默认值(不确定)。可以尝试的方法是先发制人的身份验证工作得更好:

    client.getParams().setAuthenticationPreemptive(true);
    

Otherwise, the main difference between curl -d "" and what you're doing in Java is that, in addition to Content-Length: 0, curl also sends Content-Type: application/x-www-form-urlencoded. Note that in terms of design, you should probably send an entity with your POST request anyway.

您是否尝试过(使用 HttpClient 版本4) :

String encoding = Base64.getEncoder().encodeToString((user + ":" + pwd).getBytes());
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();

一个小小的更新——希望对某些人有用——对我的项目很有用:

  • 我使用了来自 Robert Harder 的漂亮的 Public Domain 类 Base64.java (感谢 Robert-Code 可在此获得: 基地64-下载并将其放入您的包中)。

  • 下载文件(图像、文档等)并进行身份验证,然后写入本地磁盘

例如:

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

HttpBasicAuth 对我来说只有较小的更改

  1. 我用的是 Maven 依赖

    <dependency>
    <groupId>net.iharder</groupId>
    <artifactId>base64</artifactId>
    <version>2.3.8</version>
    </dependency>
    
  2. Smaller change

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

对于 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);

感谢上面的所有答案,但对我来说,我找不到 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编码做了一些更改。下面的代码将编译。

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

而使用头数组

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

使用 HTTPPOST不执行任何 Base64特定调用 登录的 简单的方法是使用 HTTPClient基本证书提供者

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