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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21998405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:56:27  来源:igfitidea点击:

Spring 4.0.0 basic authentication with RestTemplate

javaspringapachebasic-authenticationresttemplate

提问by shippi

I am currently working on integration of a third party application with our local reporting system. I would like to implement REST calls with basic authentication but facing issues in Spring 4.0.0. I have a simple solution what works nicely:

我目前正致力于将第三方应用程序与我们的本地报告系统集成。我想使用基本身份验证实现 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();

but wanted to rewrite this to use ClientHttpRequestFactoryin the following way:

但想通过以下方式重写它以使用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);
}

This code is not compiling as the CommonsClientHttpRequestFactoryclass not exists anymore in Spring 4.0.0. Do somebody know any alternative solution to this? I am quite new in this REST world therefore any help will be appreciated.

此代码未编译,因为Spring 4.0.0 中不再存在CommonsClientHttpRequestFactory类。有人知道任何替代解决方案吗?我在这个 REST 世界中很新,因此任何帮助将不胜感激。

采纳答案by Shaun the Sheep

Why not check the Spring 4 APIs to see which classes implement the required interface, namely ClientHttpRequestFactory?

为什么不检查 Spring 4 API 以查看哪些类实现了所需的接口,即ClientHttpRequestFactory

As you'll see from the Javadoc, most likely you want HttpComponentsClientHttpRequestFactory, which uses the client from Apache's HttpComponents, the successor to the old commons HttpClient.

正如您将在 Javadoc 中看到的,您很可能想要HttpComponentsClientHttpRequestFactory,它使用来自 Apache 的 HttpComponents 的客户端,旧公地的继承者HttpClient

回答by Anton Kurniawan

From http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/with HttpClient 4.3 edits:

http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/与 HttpClient 4.3 编辑

Both Spring 3.0 and 3.1 and now 4.x have very good support for the Apache HTTP libraries:

Spring 3.0 和 3.1 以及现在的 4.x 都对Apache HTTP 库有很好的支持:

  1. Spring 3.0, the CommonsClientHttpRequestFactoryintegrated with the now end of lifed HttpClient 3.x
  2. Spring 3.1introduced support for the current HttpClient 4.xvia HttpComponentsClientHttpRequestFactory(support added in the JIRA SPR-6180)
  3. Spring 4.0introduced async supportvia the HttpComponentsAsyncClientHttpRequestFactory
  1. Spring 3.0CommonsClientHttpRequestFactory与现已终止的 HttpClient 3.x集成
  2. 弹簧3.1的引入支持当前的HttpClient 4.x的经由HttpComponentsClientHttpRequestFactory(支撑在所添加JIRA SPR-6180
  3. 春4.0引入了异步支持通过HttpComponentsAsyncClientHttpRequestFactory

Let's start setting things up with HttpClient 4 and Spring 4.

让我们开始设置 HttpClient 4 和 Spring 4。

The RestTemplatewill require an HTTP request factory – a factory that supports Basic Authentication– so far, so good. However, using the existing HttpComponentsClientHttpRequestFactorydirectly will prove to be difficult, as the architecture of RestTemplatewas designed without good supportfor HttpContext– an instrumental piece of the puzzle. And so we'll need to subclass HttpComponentsClientHttpRequestFactoryand override the createHttpContextmethod: (taken from soluvas-framework on GitHub)

RestTemplate将需要一个 HTTP 请求工厂——一个支持基本身份验证的工厂——到目前为止,一切都很好。然而,使用现有HttpComponentsClientHttpRequestFactory直接将被证明是困难的,因为的体系结构RestTemplate设计没有很好的支持HttpContext-器乐一块拼图。所以我们需要子类化HttpComponentsClientHttpRequestFactory并覆盖该createHttpContext方法:(取自 GitHub 上的 soluvas-framework

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

}

It is here – in the creation of the HttpContext– that the basic authentication support is built in. As you can see, doing preemptive Basic Authentication with HttpClient 4.xis a bit of a burden: the authentication info is cached and the process of setting up this authentication cache is very manual and unintuitive.

正是在这里-在创造的HttpContext-这基本验证支持是建立在你可以看到,做先发制人。基本身份验证与HttpClient的4.x的一个有点负担:认证信息被缓存的进程设置这个身份验证缓存是非常手动和不直观的

And with that, everything is in place – the RestTemplatewill now be able to support the Basic Authenticationscheme; a simple usage pattern would be:

至此,一切就绪——RestTemplate现在将能够支持基本身份验证方案;一个简单的使用模式是:

final AuthHttpComponentsClientHttpRequestFactory requestFactory =
    new AuthHttpComponentsClientHttpRequestFactory(
                httpClient, host, userName, password);
final RestTemplate restTemplate = new RestTemplate(requestFactory);

And the request:

和请求:

restTemplate.get(
    "http://localhost:8080/spring-security-rest-template/api/foos/1",
    Foo.class);

For an in depth discussion on how to secure the REST Service itself, check out this article.

有关如何保护 REST 服务本身的深入讨论,请查看这篇文章

回答by Shiraaz.M

I know that this is an old question, but I was looking for the answer to this myself. You need to add a RestTemplate interceptor when configuring the RestTemplate. An example below in annotation configuration:

我知道这是一个老问题,但我自己也在寻找答案。配置 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;
}

Javadoc for BasicAuthorizationInterceptor.

BasicAuthorizationInterceptor 的Javadoc 。

I was stuck on this for a good few hours. Maybe it will help somebody out in the near future.

我被困在这个问题上好几个小时。也许它会在不久的将来帮助某人。

回答by Yalamanda

I have another solution to set basic authentication for customized rest template.

我有另一种解决方案来为自定义休息模板设置基本身份验证。

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;

回答by gogstad

If you prefer simple over complex, then just set the header

如果您更喜欢简单而不是复杂,那么只需设置标题

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

I'm sure there's some other Base64-library out there if the encoding that ships with the JDK is too verbose for you.

如果 JDK 附带的编码对您来说太冗长,我敢肯定还有其他一些 Base64 库。

回答by Ruslan Stelmachenko

Since Spring 4.3.1 there is a simplier way using BasicAuthorizationInterceptor, which is also independent of underlying http client used in RestTemplate.

从 Spring 4.3.1 开始,有一种更简单的使用方式BasicAuthorizationInterceptor,它也独立于RestTemplate.

The example that uses RestTemplateBuilderfrom spring-bootto add BasicAuthorizationInterceptorto RestTemplate:

使用RestTemplateBuilderfrom 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();
    }

}

This way anyrequest sent using myRestTemplatebean instance will include given basic authorization header. So be careful to not use the same RestTemplatebean instance to send requests to foreign domains. The rootUriis partially protects from this, but you can always pass the absolute URL when making the request using RestTemplateinstance, so be careful!

这样,使用bean 实例发送的任何请求myRestTemplate都将包含给定的基本授权标头。所以要小心不要使用同一个RestTemplatebean 实例向外部域发送请求。该rootUri部分是从该保护,但使用提出请求时,你总是可以传递绝对URLRestTemplate实例,所以一定要小心!

If you are not using spring-boot, you can also manually add this interceptor to your RestTemplatefollowing thisanswer.

如果您不使用spring-boot,您还可以手动将此拦截器添加到您的RestTemplate以下答案中。