使用HttpUrlConnection进行HTTP摘要认证

10
我正在尝试使用摘要认证连接到我的机器上的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开发人员,我想问一下是否有人对我的实现有什么想法或发现错误。

提前感谢您!


通常情况下,如果摘要认证不是必须的,最好使用HTTPS连接和一些标准的基于HTML的身份验证表单,因为HTTP身份验证不支持“注销”,除非客户端关闭Web浏览器。 - Kel
5个回答

5
摘要认证比仅发送username:password(这实际上是基本身份验证...并且username:password元组需要进行Base64编码!)复杂得多。您可以在此处阅读有关摘要的所有内容。(链接) 如果您不需要使用HttpUrlConnection,请查看这两个项目:它们都已经支持了摘要(和其他有用的东西)。

2

我可以通过以下代码完成它,请告诉我是否遗漏了什么;

        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方法...有没有更新的示例? - Rafael
这与摘要认证无关,这是基本的HTTP身份验证 ;) - Sobvan
OP要求使用HttpURLConnection,但这里使用的是Apache HTTP Client。 - Alex R

2

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


1
使用以下代码,如果您的服务器不需要“opaque”返回,则可正常工作。
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);

5
为了帮助未来遇到同样问题的用户,提供上下文和解释将会非常有帮助。 - StormeHawke
1
OP 要求使用 HttpURLConnection,而此处使用的是 Apache HTTP Client。 - Alex R

1

奇怪的是,使用此代码,Digest身份验证在jdk上可以原生地工作,而基本身份验证则不行:

Authenticator.setDefault(new Authenticator() {

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {

        return new PasswordAuthentication (
            "username",
            "password".toCharArray()
        );
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接