【问题标题】:Http Basic Authentication in Java using HttpClient?使用 HttpClient 在 Java 中进行 Http 基本身份验证?
【发布时间】: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。

标签: java http apache-commons


【解决方案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 对我来说只需较小的更改

      1. 我使用maven依赖

        <dependency>
            <groupId>net.iharder</groupId>
            <artifactId>base64</artifactId>
            <version>2.3.8</version>
        </dependency>
        
      2. 较小的变化

        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 请求的实体。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-07
            • 2017-05-25
            相关资源
            最近更新 更多