12

我一直在查看摘要身份验证示例:

http://hc.apache.org/httpcomponents-client-4.3.x/examples.html

在我的场景中,有多个线程发出 HTTP 请求,并且每个线程都必须使用自己的一组凭据进行身份验证。此外,请考虑这个问题对于 Apache HTTP 客户端 4.3 及以后的版本可能非常具体,4.2 可能以不同的方式处理身份验证,尽管我自己没有检查过。也就是说,有一个实际的问题。

我只想使用一个客户端实例(类的静态成员,即线程安全)并为其提供一个连接管理器来支持多个并发请求。关键是每个请求都将提供不同的凭据,并且我没有看到为每个请求分配凭据的方法,因为在构建 http 客户端时设置了凭据提供程序。从上面的链接:

[...]

    HttpHost targetHost = new HttpHost("localhost", 80, "http");
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(
            new AuthScope(targetHost.getHostName(), targetHost.getPort()),
            new UsernamePasswordCredentials("username", "password"));
    CloseableHttpClient httpclient = HttpClients.custom()
            .setDefaultCredentialsProvider(credsProvider).build();

[...]

检查:

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html#d5e600

第 4.4 节中的代码示例(寻求4.4. HTTP 身份验证和执行上下文)似乎是说 HttpClientContext 被赋予了身份验证缓存和凭据提供程序,然后被传递给 HTTP 请求。在它旁边执行请求,似乎客户端将在 HTTP 请求中获得主机过滤的凭据。换句话说:如果上下文(或缓存)具有当前 HTTP 请求的目标主机的有效凭据,他将使用它们。对我来说问题是不同的线程将对同一主机执行不同的请求。

有没有办法为每个 HTTP 请求提供自定义凭据?

在此先感谢您的时间!:)

4

2 回答 2

14

对我来说问题是不同的线程将对同一主机执行不同的请求。

为什么这会是个问题?只要您为每个线程使用不同的 HttpContext 实例,这些线程的执行上下文将完全独立

CloseableHttpClient httpclient = HttpClients.createDefault();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user:pass"));
HttpClientContext localContext = HttpClientContext.create();
localContext.setCredentialsProvider(credentialsProvider);

HttpGet httpget = new HttpGet("http://localhost/");

CloseableHttpResponse response = httpclient.execute(httpget, localContext);
try {
    EntityUtils.consume(response.getEntity());
} finally {
    response.close();
}
于 2013-10-08T18:15:45.497 回答
0

我有一个类似的问题。

我必须使用单个系统用户调用 n 次服务,并使用 NTLM 进行身份验证。我想使用多个线程来做到这一点。我想出的是创建一个没有默认凭据提供程序的 HTTPClient。当需要执行请求时,我使用注入的 CredentialProviderFactory 到执行请求的方法中(在特定线程中)。使用它我得到一个全新的 CredentialsProvider 并将它放入一个上下文(在线程中创建)。然后我使用重载调用客户端上的执行方法execute(method, context)

class MilestoneBarClient implements IMilestoneBarClient {

private static final Logger log = LoggerFactory.getLogger(MilestoneBarClient.class);
private MilestoneBarBuilder builder;
private CloseableHttpClient httpclient;
private MilestoneBarUriBuilder uriBuilder;
private ICredentialsProviderFactory credsProviderFactory;


MilestoneBarClient(CloseableHttpClient client, ICredentialsProviderFactory credsProviderFactory, MilestoneBarUriBuilder uriBuilder) {
    this(client, credsProviderFactory, uriBuilder, new MilestoneBarBuilder());
}

MilestoneBarClient(CloseableHttpClient client, ICredentialsProviderFactory credsProviderFactory, MilestoneBarUriBuilder uriBuilder, MilestoneBarBuilder milestoneBarBuilder) {
    this.credsProviderFactory = credsProviderFactory;
    this.uriBuilder = uriBuilder;
    this.builder = milestoneBarBuilder;
    this.httpclient = client;
}

// This method is called by multiple threads
@Override
public MilestoneBar get(String npdNumber) {
    log.debug("Asking milestone bar info for {}", npdNumber);

    try {
        String url = uriBuilder.getPathFor(npdNumber);
        log.debug("Building request for URL {}", url);
        HttpClientContext localContext = HttpClientContext.create();
        localContext.setCredentialsProvider(credsProviderFactory.create());

        HttpGet httpGet = new HttpGet(url);

        long start = System.currentTimeMillis();
        try(CloseableHttpResponse resp = httpclient.execute(httpGet, localContext)){
[...]

由于某些原因,我有时会遇到错误,但我想这是一个 NTLMCredentials 问题(不是线程安全的......)。

在您的情况下,您可能可以将工厂传递给 get 方法,而不是传递创建。

于 2015-10-28T13:09:35.623 回答