我一直在查看摘要身份验证示例:
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被赋予了auth缓存和凭证提供程序,然后被传递给HTTP请求。在它旁边执行请求,似乎客户端将在HTTP请求中获得主机的凭据过滤。换句话说:如果上下文(或缓存)具有当前HTTP请求的目标主机的有效凭据,则他将使用它们。对我来说,问题是不同的线程会对同一主机执行不同的请求。
有没有办法为每个HTTP请求提供自定义凭据?
提前感谢您的时间! :)
答案 0 :(得分:13)
对我来说,问题是不同的线程会对同一主机执行不同的请求。
为什么这会成为问题?只要你为每个线程使用不同的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();
}
答案 1 :(得分:0)
我有类似的问题。
我必须使用单个系统用户调用n次服务,并使用NTLM进行身份验证。我想使用多个线程来做到这一点。
我想到的是创建一个没有默认凭据提供程序的HTTPClient。当需要执行请求时,我在执行请求的方法中使用注入的CredentialProviderFactory(在特定的线程中)。使用这个我得到一个全新的CredentialsProvider,我将它放入一个Context(在线程中创建)。
然后我使用重载execute(method, context)
调用客户端上的execute方法。
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方法,而不是传递创建。