使用当前 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 【问题描述】:我正在尝试使用 RestTemplate 和 httpclient (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);
【讨论】:
我会试一试,然后告诉你结果如何 - 谢谢。 快速跟进 - 用户名和密码究竟是如何设置的? 你可以使用 UserNamePasswordCredentialsUsernamePasswordCredentials 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 配置为执行 preemptive 或 non-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)的使用与总结
Android API 23 - HttpClient 4.X 重新打包
如何从 Apache HttpClient 4.x 获取 cookie?