使用当前 httpclient (4.x) 的 RestTemplate 基本或摘要身份验证

Posted

技术标签:

【中文标题】使用当前 httpclient (4.x) 的 RestTemplate 基本或摘要身份验证【英文标题】:RestTemplate basic or digest Authentication with the current httpclient (4.x) 【发布时间】:2012-03-11 16:53:28 【问题描述】:

我正在尝试使用 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 );

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

【问题讨论】:

您能发布更详细的 HTTP 请求和响应日志吗?在尝试对您的客户端代码进行故障排除之前,确认身份验证挑战之类的事情会很有用。 希望不会有任何挑战 - 我想要抢先式身份验证。至于客户端代码 - 我真的在寻找任何可以使用 Spring RestTemplate 和 HTTPClient (4.x) 的设置。 【参考方案1】:

尝试实现自己的 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);

【讨论】:

我会试一试,然后告诉你结果如何 - 谢谢。 快速跟进 - 用户名和密码究竟是如何设置的? 你可以使用 UserNamePasswordCredentials UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(getUsername(),getPassword()); client.getCredentialsProvider().setCredentials(new AuthScope(getHost(), getPort(), AuthScope.ANY_REALM), credentials); 并且只需使用之前工厂的客户端HttpComponentsClientHttpRequestFactory requestFactory = new PreEmptiveAuthHttpRequestFactory(client); 如果你添加方案这也支持https:HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());【参考方案2】:

我修改了原答案:

添加了 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;
    

【讨论】:

【参考方案3】:

借助最新版本的 Spring 和 HttpClient,他们让基本身份验证和摘要式身份验证变得非常容易。

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


配置 RestTemplate

我们可以将 RestTemplate 配置为执行 preemptivenon-preemptive(默认)基本或摘要式身份验证。

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

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

【讨论】:

我继承了试图进行抢先式摘要身份验证的代码。这个答案有助于识别这一点,将其替换为更简单的非抢占式,丢弃旧代码并最终通过 Asterisk 的身份验证。谢谢。

以上是关于使用当前 httpclient (4.x) 的 RestTemplate 基本或摘要身份验证的主要内容,如果未能解决你的问题,请参考以下文章

异步httpclient(httpasyncclient)的使用与总结

HttpClient的使用

Android API 23 - HttpClient 4.X 重新打包

如何从 Apache HttpClient 4.x 获取 cookie?

commons.httpclient-3.X.jar 和 httpclient-4.x.jar是个啥关系

使用Apache HttpClient 4.x进行异常重试