使用 Java & 进行摘要身份验证Apache 客户端:始终 401 未经授权 [英] Digest auth with Java & Apache client : Always 401 Unauthorized

查看:52
本文介绍了使用 Java & 进行摘要身份验证Apache 客户端:始终 401 未经授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 HTTP 客户端实现摘要身份验证,但目前不起作用.

I'm trying to implement digest auth with an HTTP client, but this does not work at the moment.

有人可以检查此代码是否正确吗?出于测试目的,我使用 http://httpbin.org/,但我得到的只是 HTTP/1.1 401未经授权.

Can someone check if this code is correct? For testing purpose I use http://httpbin.org/, but all I get is HTTP/1.1 401 Unauthorized.

示例代码如下:

private static void doDigestAuth() throws ClientProtocolException,
    IOException,
    AuthenticationException,
    MalformedChallengeException
{

    HttpHost target = new HttpHost("httpbin.org", 80, "http");
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(new AuthScope(target.getHostName(), target.getPort()), new UsernamePasswordCredentials(
        "user", "passwd"));
    CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
    try {

        HttpGet httpget = new HttpGet("http://httpbin.org/digest-auth/auth/user/passwd");

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();
        // Generate DIGEST scheme object, initialize it and add it to the local
        // auth cache
        DigestScheme digestAuth = new DigestScheme();

        // Suppose we already know the realm name
        digestAuth.overrideParamter("realm", "me@kennethreitz.com");
        // // Suppose we already know the expected nonce value
        // digestAuth.overrideParamter("nonce", Long.toString(new SecureRandom().nextLong(), 36));
        // qop-value = "auth" | "auth-int" | token
        digestAuth.overrideParamter("qop", "auth");
        authCache.put(target, digestAuth);

        // Add AuthCache to the execution context
        HttpClientContext context = HttpClientContext.create();
        context.setCredentialsProvider(credsProvider);
        // context.setAuthSchemeRegistry(authRegistry);
        context.setAuthCache(authCache);

        System.out.println("Executing request " + httpget.getRequestLine() + " to target " + target);
        for (int i = 0; i < 3; i++) {
            CloseableHttpResponse response = httpclient.execute(httpget, context);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                HttpEntity entity = response.getEntity();
                InputStream instream = entity.getContent();
                // Header contentCncoding = entity .getContentEncoding();
                String contentString = IOUtils.toString(instream, null);
                System.out.println("ContentString:" + contentString);
                AuthState proxyAuthState = context.getProxyAuthState();
                System.out.println("Proxy auth state: " + proxyAuthState.getState());
                System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
                System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
                AuthState targetAuthState = context.getTargetAuthState();
                System.out.println("Target auth state: " + targetAuthState.getState());
                System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
                System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
                EntityUtils.consume(response.getEntity());
            }
            finally {
                response.close();
            }
        }
    }
    finally {
        httpclient.close();
    }

}

推荐答案

这是@heaphach 建议的 cookie 问题.线路日志(显示为日志类别 org.apache.http.wire 设置为调试)显示:
<代码><<"Set-Cookie: fake=fake_value[\r][\n]"
但 HttpClient 从不接受这个并且不会在包含完整授权"标头和摘要响应的第二个 GET 请求中使用它.因此,服务器只会忽略摘要响应.

It was a cookie problem as @heaphach suggested. The wire-log (shown with log category org.apache.http.wire set to debug) shows:
<< "Set-Cookie: fake=fake_value[\r][\n]"
but the HttpClient never picks this up and does not use it in the second GET request containing the full "Authorization" header with the digest-response. As a consequence, the server just ignores the digest response.

在我更新示例代码(也称为 抢占式 DIGEST 身份验证示例)使用下面显示的代码(从 HTTP 状态管理教程),服务器响应200 OK".

After I updated the example code (also known as the Preemptive DIGEST authentication example) with the code shown below (copied from the HTTP state management tutorial), the server responded "200 OK".

CookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("fake", "fake_value");
cookie.setDomain("httpbin.org");
cookie.setPath("/");
cookieStore.addCookie(cookie);
CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultCookieStore(cookieStore)
        .setDefaultCredentialsProvider(credsProvider)
        .build();

我还遇到了一个 gist,其中包含一些用于计算随机数"的代码所以你可以使用
digestAuth.overrideParamter("nonce", calculateNonce());
org.apache.http.impl.auth.HttpAuthenticator 不再显示错误消息在挑战中缺少随机数".

I also came across a gist containing some code to calculate a "nonce" so you can use
digestAuth.overrideParamter("nonce", calculateNonce());
and org.apache.http.impl.auth.HttpAuthenticator no longer shows the error message "missing nonce in challenge".

public static synchronized String calculateNonce() {

    Date d = new Date();
    SimpleDateFormat f = new SimpleDateFormat("yyyy:MM:dd:hh:mm:ss");
    String fmtDate = f.format(d);
    Random rand = new Random(100000);
    Integer randomInt = rand.nextInt();
    return org.apache.commons.codec.digest.DigestUtils.md5Hex(fmtDate + randomInt.toString());
}

这篇关于使用 Java &amp; 进行摘要身份验证Apache 客户端:始终 401 未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆