使用RestTemplate进行Spring 4.0.0基本身份验证

时间:2014-02-24 20:34:03

标签: java spring apache basic-authentication resttemplate

我目前正致力于将第三方应用程序与我们的本地报告系统集成。我想用基本身份验证实现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世界中相当新,因此任何帮助都将受到赞赏。

6 个答案:

答案 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库

  1. Spring 3.0 CommonsClientHttpRequestFactory与现在生命的HttpClient 3.x结束
  2. Spring 3.1 通过HttpComponentsClientHttpRequestFactory引入了对当前HttpClient 4.x 的支持(JIRA SPR-6180中添加了支持)
  3. Spring 4.0 通过HttpComponentsAsyncClientHttpRequestFactory
  4. 引入了异步支持

    让我们开始使用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-bootBasicAuthorizationInterceptor添加到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;