HttpClientBuilder basic auth

后端 未结 4 1579
旧巷少年郎
旧巷少年郎 2020-12-03 05:39

Since HttpClient 4.3, I have been using the HttpClientBuilder. I am connecting to a REST service that has basic authentication. I am setting the credentials as follows:

相关标签:
4条回答
  • 2020-12-03 05:59

    Actually, since you already trust the server, it's probably easiest to just construct the authorization header yourself.

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

    This is just one of those cases were it's easier to read the spec, and roll it yourself.

    0 讨论(0)
  • 2020-12-03 06:02

    From the Preemptive Authentication Documentation here:

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

    By default, httpclient will not provide credentials preemptively, it will first create a HTTP request without authentication parameters. This is by design, as a security precaution, and as part of the spec. But, this causes issues if you don't retry the connection, or wherever you're connecting to expects you to send authentication details on the first connection. It also causes extra latency to a request, as you need to make multiple calls, and causes 401s to appear in the logs.

    The workaround is to use an authentication cache to pretend that you've already connected to the server once. This means you'll only make one HTTP call and won't see a 401 in the logs:

    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();
        }
    }
    

    Please note: You need to trust the host you're connecting to, and if you're using HTTP, your username and password will be sent in cleartext (well, base64, but that doesn't count).

    You should also be using a much more specific Authscope rather than relying on AuthScope .ANY_HOST and AuthScope.ANY_PORT like in your example.

    0 讨论(0)
  • 2020-12-03 06:04

    I just tried your code sample (against a simple Basic Auth enabled URL) and it works fine - this is the log from the HttpClient - a bit simplified for brevity:

    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]". 
    

    So - simply put:
    - the Server does challenge the initial request
    - HttpClient recognizes the Basic Auth scheme and responds to the challenge correctly
    - at that point the Server servers the expected 200 OK

    It may be the case that the REST Service you're using isn't actually using Basic Authentication. You can try to paste the full HttpClient logs to better diagnose the issue.

    Hope that helps.

    0 讨论(0)
  • 2020-12-03 06:08

    I think HttpClient is like other curl based solution, it follows the spec.

    And the spec is "Do not send the credentials except if server tell you to do so". So you get a 401 ("I want u to send credentials")...

    It's a common soap ui problem: when you don't know, it's not obvious

    0 讨论(0)
提交回复
热议问题