apache HttpClientBuilder基本身份验证

bejyjqdl  于 2023-10-23  发布在  Apache
关注(0)|答案(5)|浏览(160)

从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)。出了什么问题?

anhgbhbe

anhgbhbe1#

抢先认证文档如下:

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

sh7euo9m

sh7euo9m2#

实际上,由于您已经信任服务器,因此自己构造授权头可能是最简单的。

byte[] credentials = Base64.encodeBase64((username + ":" + password).getBytes(StandardCharsets.UTF_8));
 request.setHeader("Authorization", "Basic " + new String(credentials, StandardCharsets.UTF_8));
 httpClient.execute(request);

这只是其中一种情况,它更容易阅读spec,并滚动它自己。

qyswt5oh

qyswt5oh3#

我刚刚尝试了你的代码示例(针对一个简单的启用了Basic Auth的URL),它工作得很好-这是来自HttpClient的日志-为了简洁起见,简化了一点:

web - 2014-01-04 12:43:19,700 [main] DEBUG o.a.h.c.protocol.RequestAddCookies - CookieSpec selected: best-match
web - 2014-01-04 12:43:19,710 [main] DEBUG o.a.h.c.protocol.RequestAuthCache - Auth cache not set in the context
web - 2014-01-04 12:43:19,728 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Opening connection {}->http://localhost:8080
web - 2014-01-04 12:43:19,730 [main] DEBUG o.a.h.c.HttpClientConnectionManager - Connecting to localhost/127.0.0.1:8080
web - 2014-01-04 12:43:19,731 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Executing request GET /spring-security-mvc-basic-auth/homepage.html HTTP/1.1
web - 2014-01-04 12:43:19,731 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED
web - 2014-01-04 12:43:19,731 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
web - 2014-01-04 12:43:19,732 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> GET /spring-security-mvc-basic-auth/homepage.html HTTP/1.1
web - 2014-01-04 12:43:19,732 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: localhost:8080
web - 2014-01-04 12:43:19,732 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.3.1 (java 1.5)
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 401 Unauthorized
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Server: Apache-Coyote/1.1
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Set-Cookie: JSESSIONID=B8E6D0D7DE0C99991A74E9B2E4EA68AE; Path=/spring-security-mvc-basic-auth/; HttpOnly
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << WWW-Authenticate: Basic realm="Baeldung"
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Length: 75
web - 2014-01-04 12:43:19,735 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Sat, 04 Jan 2014 10:43:19 GMT
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.http.impl.auth.HttpAuthenticator - Authentication required
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.http.impl.auth.HttpAuthenticator - localhost:8080 requested authentication
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Authentication schemes in the order of preference: [negotiate, Kerberos, NTLM, Digest, Basic]
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Challenge for negotiate authentication scheme not available
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Challenge for Kerberos authentication scheme not available
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Challenge for NTLM authentication scheme not available
web - 2014-01-04 12:43:19,738 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Challenge for Digest authentication scheme not available
web - 2014-01-04 12:43:19,745 [main] DEBUG o.a.http.impl.auth.HttpAuthenticator - Selected authentication options: [BASIC]
web - 2014-01-04 12:43:19,746 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Executing request GET /spring-security-mvc-basic-auth/homepage.html HTTP/1.1
web - 2014-01-04 12:43:19,746 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Target auth state: CHALLENGED
web - 2014-01-04 12:43:19,746 [main] DEBUG o.a.http.impl.auth.HttpAuthenticator - Generating response to an authentication challenge using basic scheme
web - 2014-01-04 12:43:19,747 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
web - 2014-01-04 12:43:19,747 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> GET /spring-security-mvc-basic-auth/homepage.html HTTP/1.1
web - 2014-01-04 12:43:19,747 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: localhost:8080
web - 2014-01-04 12:43:19,747 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.3.1 (java 1.5)
web - 2014-01-04 12:43:19,747 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Authorization: Basic dXNlcjE6dXNlcjFQYXNz
web - 2014-01-04 12:43:19,750 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 200 OK
web - 2014-01-04 12:43:19,750 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Server: Apache-Coyote/1.1
web - 2014-01-04 12:43:19,750 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Set-Cookie: JSESSIONID=C03FD4EB1421A4C3A003ADC895D49599; Path=/spring-security-mvc-basic-auth/; HttpOnly
web - 2014-01-04 12:43:19,750 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Type: text/html;charset=ISO-8859-1
web - 2014-01-04 12:43:19,750 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Language: en-US
web - 2014-01-04 12:43:19,751 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Length: 96
web - 2014-01-04 12:43:19,751 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Sat, 04 Jan 2014 10:43:19 GMT
web - 2014-01-04 12:43:19,751 [main] DEBUG o.a.http.impl.auth.HttpAuthenticator - Authentication succeeded
web - 2014-01-04 12:43:19,751 [main] DEBUG o.a.h.i.c.TargetAuthenticationStrategy - Caching 'basic' auth scheme for http://localhost:8080
web - 2014-01-04 12:43:19,760 [main] DEBUG o.a.h.c.p.ResponseProcessCookies - Cookie accepted: "[version: 0][name: JSESSIONID][value: C03FD4EB1421A4C3A003ADC895D49599][domain: localhost][path: /spring-security-mvc-basic-auth/][expiry: null]".

所以-简单地说:

  • 服务器会询问初始请求
  • HttpClient识别基本身份验证方案并正确响应质询
  • 此时,服务器将提供预期的200 OK
    您使用的REST服务可能实际上没有使用基本身份验证。您可以尝试粘贴完整的HttpClient日志以更好地诊断问题。
    希望能帮上忙。
8wtpewkr

8wtpewkr4#

我认为HttpClient就像其他基于curl的解决方案一样,它遵循规范。

规范是“除非服务器告诉你这样做,否则不要发送凭证”。所以你得到一个401(“我想让你发送凭据”)。
这是一个常见的soap ui问题:当你不知道的时候,

dldeef67

dldeef675#

对于使用apache http client 5的人来说,和我一样有同样的问题。
这些代码的灵感来自@Cetra,我添加了**initPreemptive()**来解决401问题。

HttpHost targetHost = new HttpHost("https", "test.com", 443);
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
AuthScope authScope = new AuthScope(targetHost);
Credentials credentials = new UsernamePasswordCredentials("username", "password".toCharArray());
credentialsProvider.setCredentials(authScope, credentials);

AuthCache authCache = new BasicAuthCache();
BasicScheme basicScheme = new BasicScheme();
// Call initPreemptive() to use Preemptive credentials
basicScheme.initPreemptive(credentials);
authCache.put(targetHost, basicScheme);

HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
context.setAuthCache(authCache);

HttpGet request = new HttpGet("https://test.com/need/basic/auth");
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
    client.execute(request, context, response -> {
        final HttpEntity responseEntity = response.getEntity();
        try {
            System.out.println("---------");
            System.out.printf("%s %s\r\n%s%n", new StatusLine(response), response.getReasonPhrase(), EntityUtils.toString(responseEntity));
            System.out.println("---------");
        } finally {
            EntityUtils.consume(responseEntity);
        }
        return null;
    });
} catch (Exception e) {
    System.out.println(e);
}

相关问题