java - HttpClientBuilder 基本认证

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

从 HttpClient 4.3 开始,我一直在使用 HttpClientBuilder。我正在连接到具有基本身份验证的 REST 服务。我按如下方式设置凭据:

HttpClientBuilder builder = HttpClientBuilder.create();

// Get the client credentials
String username = Config.get(Constants.CONFIG_USERNAME);
String password = Config.get(Constants.CONFIG_PASSWORD);

// If username and password was found, inject the credentials
if (username != null && password != null)
{
    CredentialsProvider provider = new BasicCredentialsProvider();

    // Create the authentication scope
    AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);

    // Create credential pair
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);

    // Inject the credentials
    provider.setCredentials(scope, credentials);

    // Set the default credentials provider
    builder.setDefaultCredentialsProvider(provider);
}

但是,这不起作用(我正在使用的 REST 服务返回 401)。出了什么问题?

最佳答案

来自此处的抢先身份验证文档:

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

默认情况下,httpclient 不会抢先提供凭据,它会先创建一个不带身份验证参数的 HTTP 请求。这是设计使然,作为安全预防措施,也是规范的一部分。但是,如果您不重试连接,或者您连接到的任何地方都希望您在第一次连接时发送身份验证详细信息,这会导致问题。它还会导致请求出现额外延迟,因为您需要进行多次调用,并导致 401 出现在日志中。

解决方法是使用身份验证缓存假装您已经连接到服务器一次。这意味着您只会进行一次 HTTP 调用,并且不会在日志中看到 401:

CloseableHttpClient httpclient = HttpClientBuilder.create().build();

HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
        new UsernamePasswordCredentials("username", "password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);

// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);

HttpGet httpget = new HttpGet("/");
for (int i = 0; i < 3; i++) {
    CloseableHttpResponse response = httpclient.execute(
            targetHost, httpget, context);
    try {
        HttpEntity entity = response.getEntity();

    } finally {
        response.close();
    }
}

请注意:您需要信任要连接的主机,如果您使用的是 HTTP,您的用户名和密码将以明文形式发送(好吧,base64,但这不算数)。

您还应该使用更具体的 Authscope,而不是像示例中那样依赖 AuthScope.ANY_HOSTAuthScope.ANY_PORT

关于java - HttpClientBuilder 基本认证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20914311/

相关文章:

java - JFace数据绑定(bind): Update model only if all validators succeed

javascript - 为什么会有人将(Apache mod_expires 参数)ExpiresByType 设置为 "access plus 0 seconds"?

iOS - Alamofire v2 Basic Auth 不工作

Symfony http 基本身份验证仅适用于未经身份验证的用户

Symfony2 + FOSUserBundle : http_basic authentication works, http_digest 失败

java - 如何使用私钥将 .pfx 文件转换为 keystore ?

java - 我应该遵循什么顺序来关闭 bufferedwriter 和 filewriter?

Java 电子邮件发送队列 - 固定数量的线程发送尽可能多的可用消息

python - Mod_python 不产生输出

git - 克隆 git 存储库时出错,返回错误代码 501