Spring 4.0.0 basic authentication with RestTemplate

前端 未结 6 1715
梦谈多话
梦谈多话 2020-12-13 10:37

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

相关标签:
6条回答
  • 2020-12-13 11:05

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

    The example that uses RestTemplateBuilder from spring-boot to add BasicAuthorizationInterceptor to 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 any request sent using myRestTemplate bean instance will include given basic authorization header. So be careful to not use the same RestTemplate bean instance to send requests to foreign domains. The rootUri is partially protects from this, but you can always pass the absolute URL when making the request using RestTemplate instance, so be careful!

    If you are not using spring-boot, you can also manually add this interceptor to your RestTemplate following this answer.

    0 讨论(0)
  • 2020-12-13 11:09

    Why not check the Spring 4 APIs to see which classes implement the required interface, namely 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.

    0 讨论(0)
  • 2020-12-13 11:09

    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.

    0 讨论(0)
  • 2020-12-13 11:13

    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:

    @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.

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

    0 讨论(0)
  • 2020-12-13 11:13

    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;
    
    0 讨论(0)
  • 2020-12-13 11:17

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

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

    1. Spring 3.0, the CommonsClientHttpRequestFactory integrated with the now end of lifed HttpClient 3.x
    2. Spring 3.1 introduced support for the current HttpClient 4.x via HttpComponentsClientHttpRequestFactory (support added in the JIRA SPR-6180)
    3. Spring 4.0 introduced async support via the HttpComponentsAsyncClientHttpRequestFactory

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

    The RestTemplate will require an HTTP request factory – a factory that supports Basic Authentication – so far, so good. However, using the existing HttpComponentsClientHttpRequestFactory directly will prove to be difficult, as the architecture of RestTemplate was designed without good support for HttpContext – an instrumental piece of the puzzle. And so we’ll need to subclass HttpComponentsClientHttpRequestFactory and override the createHttpContext method: (taken from soluvas-framework on GitHub)

    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.x is a bit of a burden: the authentication info is cached and the process of setting up this authentication cache is very manual and unintuitive.

    And with that, everything is in place – the RestTemplate will now be able to support the Basic Authentication scheme; a simple usage pattern would be:

    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.

    0 讨论(0)
提交回复
热议问题