我需要从Java调用REST服务,并且该服务需要摘要式身份验证。使用curl --digest -c cookie.txt ...
经过几次死胡同,我在@Ted Yang和user1107423对问题Apache HttpClient Digest authentication的回答中发现了一些有希望的伪代码。所以这就是我现在想要实现的。
到目前为止,这是我的尝试:
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.auth.*;
import org.apache.http.client.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.*;
import org.apache.http.protocol.BasicHttpContext;
[...]
private String connect(URL url, String user,
String password) throws URISyntaxException, IOException, ClientProtocolException {
HttpHost targetHost = new HttpHost(url.getHost(),
url.getPort(),
url.getProtocol());
URI uri = url.toURI();
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(user,
password));
httpclient = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider).build();
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
HttpClientContext context = HttpClientContext.create();
context.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
CookieStore cookieStore = new BasicCookieStore();
context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
@SuppressWarnings("serial")
class AuthException extends RuntimeException {
public final Header header;
public AuthException(Header header) {
this.header = header;
}
public String get(String key) {
return Arrays.stream(header.getElements())
.filter(h -> h.getName().equals(key))
.findFirst()
.map(HeaderElement::getValue)
.get();
}
}
BasicResponseHandler responseHandler = new BasicResponseHandler() {
public String handleResponse(
HttpResponse response) throws HttpResponseException, IOException {
if (response.getStatusLine().getStatusCode() == 401) {
Header header = response.getFirstHeader("WWW-Authenticate");
if (header != null) {
throw new AuthException(header);
}
}
return super.handleResponse(response);
};
};
try {
return httpclient.execute(new HttpGet(uri), responseHandler,
context);
} catch (AuthException req) {
DigestScheme digestScheme = new DigestScheme();
String realm = req.get("Digest realm");
digestScheme.overrideParamter("realm", realm);
String nonce = req.get("nonce");
digestScheme.overrideParamter("nonce", nonce);
authCache.put(targetHost, digestScheme);
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
return httpclient.execute(new HttpGet(uri),
new BasicResponseHandler(), context);
}
}
问题是我在第二个HTTP调用中仍然收到401。
可能是什么原因?
更新
我还从@ user1107423的答案中添加了digestScheme.processChallenge(req.header);
,但这没有什么不同。
这是httpclient连线日志的最新相关部分
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] .i.c.DefaultHttpClientConnectionOperator : Connection established 192.168.7.26:51130<->209.80.40.145:443
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] o.a.http.impl.execchain.MainClientExec : Executing request GET /contact/rets/login?rets-version=RETS/1.7.2 HTTP/1.1
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] o.a.http.impl.execchain.MainClientExec : Target auth state: FAILURE
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] o.a.http.impl.execchain.MainClientExec : Proxy auth state: UNCHALLENGED
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> GET /contact/rets/login?rets-version=RETS/1.7.2 HTTP/1.1
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> Host: xxxxx.org
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> Connection: Keep-Alive
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> User-Agent: Apache-HttpClient/4.5.6 (Java/1.8.0_60)
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> Cookie: JSESSIONID=01681A32C72B20D1BE4BCFE17F5A015D
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.headers : http-outgoing-1 >> Accept-Encoding: gzip,deflate
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "GET /contact/rets/login?rets-version=RETS/1.7.2 HTTP/1.1[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "Host: **xxxxxxxxxxx**[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "Connection: Keep-Alive[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "User-Agent: Apache-HttpClient/4.5.6 (Java/1.8.0_60)[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "Cookie: JSESSIONID=01681A32C72B20D1BE4BCFE17F5A015D[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2018-10-27 13:12:58.408 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 >> "[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "HTTP/1.1 401 Unauthorized[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Server: Apache-Coyote/1.1[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Set-Cookie: JSESSIONID=01681A32C72B20D1BE4BCFE17F5A015D; Path=/contact[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "MIME-Version: 1.0[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Cache-Control: private[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "RETS-Version: RETS/1.7.2[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "WWW-Authenticate: Digest realm="xxxxxxxxxx",qop="auth",nonce="b13fbc2aa074
9a42d37610c424e5d288", opaque="027f66646cdae"[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Content-Type: text/html;charset=utf-8[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Content-Length: 954[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "Date: Sat, 27 Oct 2018 20:12:56 GMT[\r][\n]"
2018-10-27 13:12:58.437 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "[\r][\n]"
2018-10-27 13:12:58.438 DEBUG 23768 --- [ main] org.apache.http.wire : http-outgoing-1 << "<html><head><title>Apache Tomcat/6.0.35 - Error report</title><style><!--H1 {fo
答案 0 :(得分:0)
原因显然是所有现有示例都不需要客户端将401响应中的opaque
和nonce
值复制到第二个请求。