我目前正致力于将第三方应用程序与我们的本地报告系统集成。我想用基本身份验证实现REST调用,但在Spring 4.0.0中遇到问题。我有一个简单的解决方案,它可以很好地运作:
final RestTemplate restTemplate = new RestTemplate();
final String plainCreds = "username:password";
final byte[] plainCredsBytes = plainCreds.getBytes();
final byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
final String base64Creds = new String(base64CredsBytes);
final HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
final HttpEntity<String> request = new HttpEntity<String>(headers);
final ResponseEntity<MyDto> response = restTemplate.exchange("myUrl", HttpMethod.GET, request, MyDto.class);
final MyDto dot = response.getBody();
但想以下列方式重写此内容以使用 ClientHttpRequestFactory :
final RestTemplate restTemplate = new RestTemplate(createSecureTransport("username", "password"));
private ClientHttpRequestFactory createSecureTransport(final String username, final String password) {
final HttpClient client = new HttpClient();
final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
client.getState().setCredentials(new AuthScope(null, 9090, AuthScope.ANY_REALM), credentials);
return new CommonsClientHttpRequestFactory(client);
}
此代码未编译,因为在Spring 4.0.0中不再存在 CommonsClientHttpRequestFactory 类。有人知道任何替代解决方案吗?我在这个REST世界中相当新,因此任何帮助都将受到赞赏。
答案 0 :(得分:33)
我知道这是一个老问题,但我一直在寻找答案。配置RestTemplate时需要添加RestTemplate拦截器。注释配置中的以下示例:
@Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(
new FormHttpMessageConverter(),
new StringHttpMessageConverter()
));
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("client", "secret"));
return restTemplate;
}
BasicAuthorizationInterceptor的Javadoc。
我被困在这几个小时。也许它会在不久的将来帮助某人。
答案 1 :(得分:18)
使用HttpClient 4.3编辑来自http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ :
Spring 3.0和3.1以及现在4.x都非常支持 Apache HTTP库:
CommonsClientHttpRequestFactory
与现在生命的HttpClient 3.x结束 HttpComponentsClientHttpRequestFactory
引入了对当前HttpClient 4.x 的支持(JIRA SPR-6180中添加了支持)HttpComponentsAsyncClientHttpRequestFactory
让我们开始使用HttpClient 4和Spring 4进行设置。
RestTemplate
将需要HTTP请求工厂 - 支持基本身份验证的工厂 - 到目前为止,非常好。但是,直接使用现有的HttpComponentsClientHttpRequestFactory
将会很困难,因为RestTemplate
的架构设计为HttpContext
HttpComponentsClientHttpRequestFactory
- 这是一个难题的工具。因此,我们需要继承createHttpContext
并覆盖package org.soluvas.commons.util;
import java.net.URI;
import javax.annotation.Nullable;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* From http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/
*
* <p>And with that, everything is in place – the {@link RestTemplate} will now be able to support the Basic Authentication scheme; a simple usage pattern would be:
*
* <pre>
* final AuthHttpComponentsClientHttpRequestFactory requestFactory = new AuthHttpComponentsClientHttpRequestFactory(
* httpClient, host, userName, password);
* final RestTemplate restTemplate = new RestTemplate(requestFactory);
* </pre>
*
* And the request:
*
* <pre>
* restTemplate.get("http://localhost:8080/spring-security-rest-template/api/foos/1", Foo.class);
* </pre>
*
* @author anton
*/
public class AuthHttpComponentsClientHttpRequestFactory extends
HttpComponentsClientHttpRequestFactory {
protected HttpHost host;
@Nullable
protected String userName;
@Nullable
protected String password;
public AuthHttpComponentsClientHttpRequestFactory(HttpHost host) {
this(host, null, null);
}
public AuthHttpComponentsClientHttpRequestFactory(HttpHost host, @Nullable String userName, @Nullable String password) {
super();
this.host = host;
this.userName = userName;
this.password = password;
}
public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host) {
this(httpClient, host, null, null);
}
public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host,
@Nullable String userName, @Nullable String password) {
super(httpClient);
this.host = host;
this.userName = userName;
this.password = password;
}
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
// 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(host, basicAuth);
// Add AuthCache to the execution context
HttpClientContext localcontext = HttpClientContext.create();
localcontext.setAuthCache(authCache);
if (userName != null) {
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(host), new UsernamePasswordCredentials(userName, password));
localcontext.setCredentialsProvider(credsProvider);
}
return localcontext;
}
}
方法:(without good support)
HttpContext
正是在这里 - 在RestTemplate
的创建中 - 内置了基本身份验证支持。正如您所看到的,使用HttpClient 4.x 执行抢占式基本身份验证是< em> taken from soluvas-framework on GitHub :身份验证信息已缓存,设置此身份验证缓存的过程非常手动且不直观。
由此,一切都已到位 - final AuthHttpComponentsClientHttpRequestFactory requestFactory =
new AuthHttpComponentsClientHttpRequestFactory(
httpClient, host, userName, password);
final RestTemplate restTemplate = new RestTemplate(requestFactory);
现在可以支持基本身份验证计划;一个简单的使用模式是:
restTemplate.get(
"http://localhost:8080/spring-security-rest-template/api/foos/1",
Foo.class);
请求:
{{1}}
有关如何保护REST服务本身的深入讨论,a bit of a burden。
答案 2 :(得分:6)
从Spring 4.3.1开始,有一种使用BasicAuthorizationInterceptor
的简化方法,它也独立于RestTemplate
中使用的底层http客户端。
使用RestTemplateBuilder
中的spring-boot将BasicAuthorizationInterceptor
添加到RestTemplate
的示例:
@Configuration
public class AppConfig {
@Bean
public RestTemplate myRestTemplate(RestTemplateBuilder builder) {
return builder
.rootUri("http://my.cool.domain/api/")
.basicAuthorization("login", "password")
.build();
}
}
这样使用myRestTemplate
bean实例发送的任何请求都将包含给定的基本授权标头。因此,请注意不要使用相同的RestTemplate
bean实例向外部域发送请求。 rootUri
部分可以防止这种情况,但您可以在使用RestTemplate
实例发出请求时始终传递绝对URL,所以要小心!
如果您没有使用spring-boot
,还可以在this回答之后手动将此拦截器添加到RestTemplate
。
答案 3 :(得分:5)
如果您更喜欢简单的复杂,那么只需设置标题
即可 HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString("myuser:mypass".getBytes(Charset.forName("UTF-8"))));
HttpEntity<SomeBody> myRequest = new HttpEntity<>(mybody, headers);
restTemplate.postForEntity(someUrl, myRequest, null);
如果JDK附带的编码对你来说过于冗长,我确定还有其他一些Base64库。
答案 4 :(得分:4)
为什么不检查Spring 4 API以查看哪些类实现了所需的接口,即ClientHttpRequestFactory
?
正如您将从Javadoc中看到的那样,您很可能希望HttpComponentsClientHttpRequestFactory
使用来自Apache的HttpComponents的客户端,这是旧公共HttpClient
的继承者。
答案 5 :(得分:0)
我有另一种解决方案来为自定义的休息模板设置基本身份验证。
RestTemplate restTemplate = new RestTemplate();
HttpHost proxy =null;
RequestConfig config=null;
String credentials = this.env.getProperty("uname") + ":" + this.env.getProperty("pwd");
String encodedAuthorization = Base64.getEncoder().encodeToString(credentials.getBytes());
Header header = new BasicHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedAuthorization);
List<Header> headers = new ArrayList<>();
headers.add(header);
// if we need proxy
if(Boolean.valueOf(env.getProperty("proxyFlag"))){
proxy = new HttpHost(this.env.getProperty("proxyHost"), Integer.parseInt(env.getProperty("proxyPort")), "http");
config= RequestConfig.custom().setProxy(proxy).build();
}else{
config= RequestConfig.custom().build();
}
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config)
.setDefaultHeaders(headers).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
restTemplate.setRequestFactory(factory);
return restTemplate;