10

我正在尝试使用RestTemplatehttpclient (4.x)进行主要(或基本)身份验证。

由于我找不到任何有关如何实际执行此操作的示例,因此我尝试了各种方法来挂钩各种 httpclient 工件,但没有运气 - 基本上,根本没有发送任何Authentication标头。

我目前的实现是:

DefaultHttpClient newHttpClient = new DefaultHttpClient();
Credentials credentials = new UsernamePasswordCredentials( username, password );
AuthScope authScope = new AuthScope( host, port, AuthScope.ANY_REALM );
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials( authScope, credentials );
newHttpClient.setCredentialsProvider( credentialsProvider );

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory( newHttpClient );
restTemplate.setRequestFactory( requestFactory );

有什么我做错了吗?在任何地方都有一个可行的例子吗?任何帮助表示赞赏。谢谢。

4

3 回答 3

9

尝试实现您自己的 RequestFactory 以实现抢先式身份验证。

public class PreEmptiveAuthHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {

public PreEmptiveAuthHttpRequestFactory(DefaultHttpClient client) {
    super(client);
}

@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
    AuthCache authCache = new BasicAuthCache();
    BasicScheme basicAuth = new BasicScheme();
    HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort());
    authCache.put(targetHost, basicAuth);
    BasicHttpContext localcontext = new BasicHttpContext();
    localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

    return localcontext;
}
}

然后就使用它:

HttpComponentsClientHttpRequestFactory requestFactory = new PreEmptiveAuthHttpRequestFactory( newHttpClient );

希望能帮助到你


如何设置用户名和密码(复制自@bifur 的评论)

您可以使用UserNamePasswordCredentials

UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(getUsername(),getPassword()); 
client.getCredentialsProvider().setCredentials(new AuthScope(getHost(), getPort(), AuthScope.ANY_REALM), credentials); 

并且只使用之前工厂的客户端

HttpComponentsClientHttpRequestFactory requestFactory = new PreEmptiveAuthHttpRequestFactory(client);
于 2012-03-30T10:34:18.227 回答
4

使用最新版本的 Spring 和 HttpClient,他们可以轻松地进行基本身份验证和摘要身份验证。

注意:我使用的是Spring Boot 2.xx(Spring Framework 5.xx)和HttpClient 4.5.x


配置 RestTemplate

我们可以将 RestTemplate 配置为进行抢占式或非抢占式(默认)基本或摘要身份验证。

非抢先式基本或摘要式身份验证设置

RestTemplate 使用非抢先式(即最初执行质询请求)基本或摘要身份验证的设置是相同的。只需通过 HttpClient 库的 CredentialsProvider 类提供用户名和密码。

HttpClient 会根据初始请求(质询请求)的 401 响应头自动检测服务器正在使用哪种认证类型,因此无需进行任何认证类型特定配置。

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    Credentials credentials = new UsernamePasswordCredentials(username, password);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, credentials);

    HttpClient httpClient = HttpClients
            .custom()
            .setDefaultCredentialsProvider(credentialsProvider)
            .build();

    return builder
            .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient))
            .build();
}

抢先式基本身份验证设置

使用抢先式基本身份验证变得更加容易,Spring 开箱即用地支持它。由于只需要用户名和密码,因此建议使用抢先式基本身份验证来消除执行质询请求的额外成本。

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
            .basicAuthorization(username, password)
            .build();
}

抢先式摘要身份验证设置

Spring 不支持开箱即用的 RestTemplate 的抢先式摘要身份验证。由于摘要身份验证需要 nonce 和可能的其他服务器生成的数据(例如不透明的),除了用户名和密码之外,它才能验证自己,因此必须至少发出一个质询请求。

鉴于此,尽管直接使用 HttpClient 的库,但仍然可以使用抢先式摘要身份验证。如果您仍然喜欢将摘要抢先式身份验证与 RestTemplate 一起使用,请注意在连接到非 Spring 摘要保护的应用程序时可能会遇到一些问题。

请参阅以前的答案以使用抢先式摘要身份验证。考虑到可能遇到的复杂性和问题,我个人不建议将抢先式摘要身份验证与 RestTemplate 一起使用。使用抢先式摘要身份验证的主要动机是出于性能目的,因此除非您对每个请求进行多次调用,否则非抢先式摘要身份验证可能是更好的选择。


使用 RestTemplate 发送请求

使用 RestTemplate 发送请求时,您不需要任何特定于身份验证类型的处理。无论您使用的是抢占式身份验证还是非抢占式身份验证,发送请求的代码都是一样的。

示例 GET 请求

String response = restTemplate.getForObject(url, String.class);
JSONObject result = new JSONObject(response);

POST 请求示例

JSONObject body = new JSONObject();
// populate body

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> request = new HttpEntity<>(body, headers);
String response = restTemplate.postForObject(url, request, String.class);
JSONObject result = new JSONObject(response);
于 2018-10-28T09:27:18.173 回答
0

我稍微修改了原始答案:

  • 添加了 https 支持
  • 更新过时的东西

    public class PreEmptiveAuthHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
    
        public PreEmptiveAuthHttpRequestFactory(HttpClient client) {
            super(client);
        }
    
        @Override
        protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
            AuthCache authCache = new BasicAuthCache();
            BasicScheme basicAuth = new BasicScheme();
            HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
            authCache.put(targetHost, basicAuth);
            HttpClientContext localContext = HttpClientContext.create();
            localContext.setAuthCache(authCache);
            return localContext;
        }
    }
    
于 2016-09-21T10:54:29.360 回答