【问题标题】:HTTP digest authentication with HttpUrlConnection使用 HttpUrlConnection 进行 HTTP 摘要身份验证
【发布时间】:2010-10-24 14:01:24
【问题描述】:

我正在尝试使用摘要式身份验证连接到我机器上的 Tomcat Web 服务器。我正在使用tomcat的内存领域。以下是服务器的配置方式:

1) 在 server.xml 中:

<Realm className="org.apache.catalina.realm.MemoryRealm" digest="MD5" />

2) 在tomcat-users.xml中

<user username="testuser" password="81dc9bdb52d04dc20036dbd8313ed055" roles="test"/>

3) 在我的 web 项目的 web.xml 中:

<auth-method>DIGEST</auth-method>

如您所见,我已将摘要方法指定为“MD5”,并使用 Tomcat 的 digest.sh 加密了密码。

这是我在客户端的代码:

private static void testGet() throws IOException {

    // Create a URL
    URL test = new URL("http://localhost:8080/TestWebProject/TestServlet");

    // Open a connection to the URL
    HttpURLConnection conn = (HttpURLConnection) test.openConnection();

    MessageDigest md5 = null;
    try {
      md5 = MessageDigest.getInstance("MD5");
    } catch(NoSuchAlgorithmException e) {
      e.printStackTrace();
    }

    // Digest password using the MD5 algorithm
    String password = "1234";
    md5.update(password.getBytes());
    String digestedPass = digest2HexString(md5.digest());

    // Set header "Authorization"
    String credentials = "testuser:" + digestedPass;
    conn.setRequestProperty("Authorization", "Digest " + credentials);

    // Print status code and message
    System.out.println("Test HTTP GET method:");
    System.out.println("Status code: " + conn.getResponseCode());
    System.out.println("Message: " + conn.getResponseMessage());
    System.out.println();

}

private static String digest2HexString(byte[] digest)
{
   String digestString="";
   int low, hi ;

   for(int i=0; i < digest.length; i++)
   {
      low =  ( digest[i] & 0x0f ) ;
      hi  =  ( (digest[i] & 0xf0)>>4 ) ;
      digestString += Integer.toHexString(hi);
      digestString += Integer.toHexString(low);
   }
   return digestString ;
}

我认为我的客户端代码和服务器的配置都可以。尽管服务器不断向我发送状态码 401,并带有消息“未经授权”。由于我不是经验丰富的 java 开发人员,所以我想问一下是否有人有想法或在我的实现中看到错误。

提前谢谢你!

【问题讨论】:

标签: java


【解决方案1】:

摘要式身份验证远比仅发送username:password 复杂得多(这实际上是基本身份验证......并且username:password 元组需要进行Base64 编码!)。

您可以阅读有关摘要here的所有内容。

如果您不需要使用HttpUrlConnection,请查看以下两个项目:

它们都已经支持 Digest(和其他有用的东西)开箱即用。

【讨论】:

    【解决方案2】:

    HttpUrlConnection 适用于简单的工作,但如果您想要更高级的功能(如摘要身份验证),我建议您使用 Commons HTTP Client.

    【讨论】:

      【解决方案3】:

      我可以按照以下代码完成它,如果我遗漏了什么,请告诉我;

              DefaultHttpClient httpclient = new DefaultHttpClient();
      
              ResponseHandler<String> responseHandler = new BasicResponseHandler();
      
              httpclient.getCredentialsProvider().setCredentials(
                      new AuthScope("localhost", 8080), 
                      new UsernamePasswordCredentials("username", "password"));   
      
              HttpGet httpget = new HttpGet(urlStr);
               System.out.println("executing request" + httpget.getRequestLine());
      
              String response = httpclient.execute(httpget, responseHandler);
              System.out.println("Response :: " + response);
      

      【讨论】:

      • DefaultHttpClient 现在已弃用并且 HttpClient 不再具有 getCredentialsProvider 方法...有人有更新的示例吗?
      • 这与摘要认证无关,这是基本的HTTP认证;)
      • OP 要求 HttpURLConnection,这是使用 Apache HTTP 客户端。
      【解决方案4】:

      使用以下代码,它可以工作如果您的服务器不需要“不透明”返回

      import org.apache.http.auth.UsernamePasswordCredentials;
      import org.apache.http.client.CredentialsProvider;
      import org.apache.http.impl.client.CloseableHttpClient;
      
      CredentialsProvider credsProvider = new BasicCredentialsProvider();
              credsProvider.setCredentials(
                      new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
                      new UsernamePasswordCredentials(username, password));
              CloseableHttpClient httpclient = HttpClients.custom()
                      .setDefaultCredentialsProvider(credsProvider)
                      .build();
      
      
      HttpResponse response = httpClient.execute(get);
      

      【讨论】:

      • 上下文和解释将有助于未来遇到此问题的用户遇到同样的问题
      • OP 要求使用 HttpURLConnection,这是使用 Apache HTTP 客户端。
      【解决方案5】:

      奇怪的是,Digest 身份验证可以在 jdk 上使用此代码进行本机工作,而 Basic auth 则不能:

      Authenticator.setDefault(new Authenticator() {
      
          @Override
          protected PasswordAuthentication getPasswordAuthentication() {
      
              return new PasswordAuthentication (
                  "username",
                  "password".toCharArray()
              );
          }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-04-25
        • 1970-01-01
        • 2011-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多