为啥来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制]
Posted
技术标签:
【中文标题】为啥来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制]【英文标题】:Why Digest authentication Java HttpClient code from other users doesn't work for me? [duplicate]为什么来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制] 【发布时间】:2018-10-27 18:59:16 【问题描述】:我需要从 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
【问题讨论】:
【参考方案1】:原因显然是所有预先存在的示例都不需要客户端从对第二个请求的 401 响应中复制 opaque
和 nonce
值。
【讨论】:
以上是关于为啥来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 SQL Server 不允许我启用混合身份验证模式,以便我可以使用 sa 用户将角色分配给其他用户?
Kong Basic Auth 使用来自其他服务的身份验证来授权路由请求
如何在 android 中使用 volley 实现 Digest 身份验证