使用 HttpClient 在 Java 中进行 Http 基本身份验证?
Posted
技术标签:
【中文标题】使用 HttpClient 在 Java 中进行 Http 基本身份验证?【英文标题】:Http Basic Authentication in Java using HttpClient? 【发布时间】:2011-03-18 00:41:41 【问题描述】:我正在尝试在 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();
【问题讨论】:
嗯,服务器日志中显示的错误是什么? 啊...我无权访问服务器日志 :( 大多数时候我们使用的授权密钥可能是错误的。检查dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm 以查看您是否使用了正确的密钥。我在为 firebase 选择 API 密钥时也感到困惑我们必须在 firebase 设置下的 Cloud 消息选项卡中使用 SENDER ID - API KEY 对。即转到 firebase App--> Go to app setting --> Cloud Messaging 在那里你可以找到 Sender Id API key 和这个 API key 你可以用来发送 FCM。 【参考方案1】:您是否尝试过(使用 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();
【讨论】:
从 Java 8 开始最好使用java.util.Base64
:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
我更喜欢使用 javax.xml.bind.DatatypeConverter 从到 base64、hex 和其他转换。它是 jdk 的一部分,因此无需包含任何额外的 JAR。
这是适用于我的用例的版本,其中已经提供了 HttpClient,并且在构建 httpclient 时您无法在构建器上设置 setDefaultCredentialsProvider()。我也喜欢它,因为它是每个调用范围。不在整个 httpclient 范围内。【参考方案2】:
使用 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】:使用 HTTP POST 不执行任何 Base64 特定调用的简单方法是使用 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);
【讨论】:
这对我不起作用。调用有效,但不存在身份验证标头。 奇怪,你的provider设置正确了吗? 也尝试更新你的库的版本。这对我有用 对于基本身份验证文件下载它对我有用,但我使用 HttpGet 而不是 HttpPost。谢谢。【参考方案4】:好的,所以这个工作。以防万一有人想要它,这是适合我的版本:)
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();
【讨论】:
找不到Base64Encoder
。乔纳斯你能把完整的罐子给吗?还有Base64Encoder
的完全限定类名是什么?
@Amitabh:对于Base64Encoder
,请查看here。对于Base64
,请查看 4.2.5.zip 中的 commons-codec-1.6.jar,地址为 Apache HttpComponents Downloads、doc、import org.apache.commons.codec.binary.Base64;
这没有回答问题。该问题询问有关使用 HttpClient 的问题,而此答案不使用 HttpClient。
如果您使用的是 Java 8,则可以使用 java.util.Base64。
这是 java.util.Base64 String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
的行【参考方案5】:
这是上面接受的答案中的代码,对 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();
【讨论】:
【参考方案6】:HttpBasicAuth 对我来说只需较小的更改
我使用maven依赖
<dependency>
<groupId>net.iharder</groupId>
<artifactId>base64</artifactId>
<version>2.3.8</version>
</dependency>
较小的变化
String encoding = Base64.encodeBytes ((user + ":" + passwd).getBytes());
【讨论】:
【参考方案7】:感谢以上所有答案,但对我来说,我找不到 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() 也为我工作。可能是您在较早的情况下在消息正文中犯了错误,从而导致了错误的请求。或者可能取决于服务器。【参考方案8】:对于 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);
【讨论】:
【参考方案9】:一个小更新 - 希望对某人有用 - 它适用于我的项目:
我使用来自 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();
【讨论】:
我收到The method encodeBytes(byte[]) is undefined for the type Base64
自定义Base64类可以用import org.apache.commons.codec.binary.Base64;
替换成detailed in this answer on this page
在java 8中,可以使用:import java.util.Base64;【参考方案10】:
这里有几点:
您可以考虑升级到 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
请求的实体。
【讨论】:
以上是关于使用 HttpClient 在 Java 中进行 Http 基本身份验证?的主要内容,如果未能解决你的问题,请参考以下文章
HttpClient--使用HttpClient进行Get Post请求访问
尝试在 Java 中使用 HttpClient 发送 HTTP Post GraphQL 查询时出现 HTTP 400
如何在 Jetty HttpClient 中进行多部分/表单数据发布