【问题标题】:HTTPClient sends out two requests when using Basic Auth?HTTPClient 在使用 Basic Auth 时发出两个请求?
【发布时间】:2013-02-26 23:18:53
【问题描述】:

我一直在使用 HTTPClient 版本 4.1.2 来尝试通过需要基本身份验证的 HTTP API 访问 REST。这是客户端代码:

DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager());
// Enable HTTP Basic Auth
httpClient.getCredentialsProvider().setCredentials(
    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
    new UsernamePasswordCredentials(this.username, this.password));

HttpHost proxy = new HttpHost(this.proxyURI.getHost(), this.proxyURI.getPort());

httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, proxy);

当我构造一个POST 请求时,像这样:

HttpPost request = new HttpPost("http://my/url");
request.addHeader(new BasicHeader("Content-type", "application/atom+xml; type=entry")); // required by vendor
request.setEntity(new StringEntity("My content"));

HttpResponse response = client.execute(request);

我在Charles Proxy 中看到有两个请求正在发送。一个没有Authorization: Basic ... 标头,一个有。如您所料,第一个以 401 失败,但第二个以 201 正常。

有人知道为什么会这样吗?谢谢!

编辑:

我应该明确指出我已经查看了this question,但正如您所见,我以同样的方式设置了AuthScope,但它并没有解决我的问题。另外,我每次发出请求时都会创建一个新的HttpClient(尽管我使用相同的ConnectionManager),但即使我对多个请求使用相同的HttpClient,问题仍然存在。

编辑 2:

所以看起来@LastCoder 建议的方法就是这样做。关于另一个问题,请参阅this answer。问题源于我对 HTTP 规范缺乏了解。我要做的就是所谓的“抢先式身份验证”和HttpClientdocs mention it here。值得庆幸的是,上面链接的答案是一种更短更简洁的方法。

【问题讨论】:

  • 我注意到使用soap-ui时发生了同样的事情,即使指定了凭据。
  • 我想知道这是否真的是正常行为。客户端发出一个不假设任何身份验证的 http 请求,然后被告知(通过 401)需要基本身份验证。理论上基本身份验证可以先发制人完成,但其他身份验证方案(例如摘要)需要额外协商
  • @seand 你知道我确实考虑过这一点,但我不知道这是否内置在 HTTP 协议中或类似的东西中。
  • @devslab http 客户端可以预先发送基本的身份验证标头(@LastCoder 提到了如何做到这一点)。我在想 HttClient 不知道服务器需要基本身份验证。你事先告诉它信用,但没有告诉它协议。如果有办法告诉它“这是基本的”身份验证,它可能会减少额外的跳跃。
  • 原来@LastCoder 发现这样做是 HTTP 规范的一部分。

标签: java basic-authentication apache-httpclient-4.x


【解决方案1】:

为什么不使用 .setCredentials() 编码 USERNAME:PASSWORD 并使用 .addHeader() 添加身份验证标头

【讨论】:

  • 我当然可以这样做,我会测试看看这是否会有所不同,但根据HttpClient repo 中的示例代码 (bit.ly/wEsEhY),我应该这样做去做吧。
  • @daveslab - 这是 http 客户端规范的一部分,首先匿名请求资源并使用 Authorization 标头响应 401。如果不是客户端将使用 Web 服务器甚至不需要的 Authorization 标头凭据向 Web 服务器发送垃圾邮件。这只是基本的安全最佳实践。
  • 这是一个蛮力解决方案,但如果需要,切换协议会变得更加困难(例如,如果服务器更改为使用摘要身份验证)
  • @LastCoder 的评论就是这个问题的答案
【解决方案2】:

这意味着您的服务器/目标端点正在为每个客户端请求创建一个新会话。这迫使您的每个请求都经过握手,这意味着客户端首先拨打电话并意识到它需要授权,然后再进行授权。您需要做的是抢先发送授权如下:

httpClient.getParams().setAuthenticationPreemptive(true);

只是为了了解您可以记录客户端请求标头的过程,以便您了解客户端发送和接收的内容: 看看这是否有效。

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多