Spring RestTemplate gives 401 Unauthorized error w

2019-07-25 00:33发布

问题:

I am trying to hit one Microsoft Flow POST URL in my Spring Rest application using following code but it is giving me 401 error. My Code:

    @RequestMapping(value = "/hookslistner", method = RequestMethod.POST)
    public ResponseEntity<Void> recieveWebhook(@RequestBody InventorySystemModel inventory,
            @RequestHeader("event") String event,
            @RequestHeader("Authorization") String authorization) {
// authorization = "Basic <Base64 encoded value of username:pwd>"

        RestTemplate restTemplate = new RestTemplate();

        org.springframework.http.HttpHeaders httpHeaders = new org.springframework.http.HttpHeaders();

        String url = "https://prod-01.centralindia.logic.azure.com/workflows/835348<hiding rest of part>";        
        String headerName = "Authorization";
        httpHeaders.add(headerName, authorization);
        httpHeaders.add("Content-Type", "application/json");
        HttpEntity<String> requestEntity = new HttpEntity<>("Headers", httpHeaders);
        System.out.println(">>>>>>>" + restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class).getBody());
    }

Error:

SEVERE: Servlet.service() for servlet [webhooks] in context with path [/inventoryhooks] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 Unauthorized] with root cause
org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
.
.
.

Is it because my target url is https and my localhost is http?

Can anyone point me what is going wrong?

回答1:

Two points for you to check for this problem:

  1. if the target server is a http server, then you shouldn't use https in the url.
  2. make sure the authorization value is base64 encoded.

Update:

Since the target server is a https server, the problem is that you haven't configured ssl info into the RestTempalte. You can refer to the following code snippet to get a ssl restTemplate:

@Configuration
public class RestClientConfig {
    @Bean
    public RestOperations restOperations(ClientHttpRequestFactory clientHttpRequestFactory) throws Exception {
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
        return new HttpComponentsClientHttpRequestFactory(httpClient);
    }

    @Bean
    public HttpClient httpClient(@Value("${keystore.file}") String file, @Value("${keystore.pass}") String password) throws Exception {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream inStream = new FileInputStream(file);
        try {
            trustStore.load(inStream, password.toCharArray());
        } finally {
            inStream.close();
        }

        SSLContext sslcontext =
                SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        SSLConnectionSocketFactory sslsf =
                new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null,
                                               null);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

The test case:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RestClientConfig.class)
public class RestClientTest {

    @Autowired
    private RestOperations rest;

    private HttpHeaders getHeaders(){
        String plainCredentials="admin:admin";
        String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + base64Credentials);
        return headers;
    }

    @Test
    public void test() {
        HttpEntity<String> request = new HttpEntity<String>(getHeaders());
        ResponseEntity<String> response = rest.exchange(url, HttpMethod.GET, request, String.class);
        System.out.println(response.getBody());
    }
}