使用restTemplate发送带有身份验证标头的GET请求


76

我需要通过使用RestTemplate发送带有一些Authorization标头的GET请求来从服务器中检索资源。

浏览文档后,我注意到没有GET方法将标头作为参数接受,并且发送标头(例如accept和Authorization)的唯一方法是使用交换方法。

由于这是一个非常基本的动作,所以我想知道我是否缺少某些东西,还有另外一种更简单的方法吗?

Answers:


66

您什么都不会错过。RestTemplate#exchange(..)是用于设置请求标头的适当方法。

这是一个示例(使用POST,但只需将其更改为GET并使用所需的实体)。

这是另一个例子。

请注意,使用GET,您的请求实体不必包含任何内容(除非您的API期望它包含,但这将违反HTTP规范)。它可以是一个空字符串。


1
但是,如果您希望get请求方法映射到一个对象但仍希望发送标题,该怎么办?
user2725919

50

您可以使用postForObjectHttpEntity。它看起来像这样:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer "+accessToken);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);

在GET请求中,通常不发送正文(允许,但没有任何作用)。添加标头而不用其他方式连接RestTemplate的方法是直接使用exchangeorexecute方法。get简写不支持标头修改。

乍一看,这种不对称有点怪异,也许这将在Spring的未来版本中得到解决。


4
restTemplate.postForEntity(url, entity, String.class)也可以。
阿卜杜勒16-09-15

问题是关于GET请求,但这个答案是关于POST。这是误导。没有getForObject这样的签名。
Zon

26

这是一个具有基本身份验证,标头和异常处理的超简单示例。

private HttpHeaders createHttpHeaders(String user, String password)
{
    String notEncoded = user + ":" + password;
    String encodedAuth = "Basic " + Base64.getEncoder().encodeToString(notEncoded.getBytes());
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", encodedAuth);
    return headers;
}

private void doYourThing() 
{
    String theUrl = "http://blah.blah.com:8080/rest/api/blah";
    RestTemplate restTemplate = new RestTemplate();
    try {
        HttpHeaders headers = createHttpHeaders("fred","1234");
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
        System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
    }
    catch (Exception eek) {
        System.out.println("** Exception: "+ eek.getMessage());
    }
}

2
不知道为什么这最初被否决了。如果您是第一个拒绝投票的人,请随时在评论中进行解释。
Sander Verhagen

2
“基本”部分不应该编码,应该编码吗?
Wenneguen

1
createHttpHeaders方法略有错误。字符串notEncoded =用户+“:” +密码;... headers.add(“ Authorization”,“ Basic” + encodingAuth);
Milind

我还发现,“基本”也不应编码。这是一个很好的示例,说明了如何使用我本人使用的身份验证,但是更正编码将是不错的选择。
Tim Holt

修复了上面评论中提到的基本编码
Adriaan Koster,

10

所有这些答案似乎都不完整和/或不正确。查看RestTemplate接口,可以确定它似乎打算ClientHttpRequestFactory注入其中,然后将使用requestFactory创建请求,包括标头,正文和请求参数的任何自定义。

您要么需要通用ClientHttpRequestFactory的注入单个共享,RestTemplate要么需要通过获取新的模板实例new RestTemplate(myHttpRequestFactory)

不幸的是,即使您只想设置一个Authorization标头,创建这样的工厂似乎也不是一件容易的事,考虑到可能有一个常见的要求,这非常令人沮丧,但是至少在例如这样的情况下,它很容易使用,您的Authorization标头可以从Spring-SecurityAuthorization对象中包含的数据中创建,然后您可以创建一个工厂,该工厂通过执行SecurityContextHolder.getContext().getAuthorization()然后填充标头来设置每个请求的传出AuthorizationHeader ,并酌情使用null检查。现在,使用该RestTemplate进行的所有出站rest调用都将具有正确的Authorization标头。

在没有更加强调HttpClientFactory机制的情况下,它为常见情况提供了易于重载的基类,例如将单个标头添加到请求中,RestTemplate最终,大多数很好的便捷方法最终都浪费了时间,因为它们很少使用。

我希望看到类似这样的简单内容

@Configuration
public class MyConfig {
  @Bean
  public RestTemplate getRestTemplate() {
    return new RestTemplate(new AbstractHeaderRewritingHttpClientFactory() {
        @Override
        public HttpHeaders modifyHeaders(HttpHeaders headers) {
          headers.addHeader("Authorization", computeAuthString());
          return headers;
        }
        public String computeAuthString() {
          // do something better than this, but you get the idea
          return SecurityContextHolder.getContext().getAuthorization().getCredential();
        }
    });
  }
}

目前,可用ClientHttpRequestFactory的接口很难与之交互。更好的做法是为现有工厂实现提供一个抽象包装,这使它们看起来像一个更抽象的对象(如AbstractHeaderRewritingRequestFactory),以仅替换一项功能。目前,它们是非常通用的,因此即使编写这些包装也是一项复杂的研究。


2
当您的“答案”非常有趣时,它看起来更像是评论,而不是实际答案。
马丁·施罗德(MartinSchröder)'18年

3

这些天,下面的内容就足够了:

HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
restTemplate.exchange(RequestEntity.get(new URI(url)).headers(headers).build(), returnType);

0

一个简单的解决方案是在RestTemplate的Bean配置中配置所有调用所需的静态http标头:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate getRestTemplate(@Value("${did-service.bearer-token}") String bearerToken) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add((request, body, clientHttpRequestExecution) -> {
            HttpHeaders headers = request.getHeaders();
            if (!headers.containsKey("Authorization")) {
                String token = bearerToken.toLowerCase().startsWith("bearer") ? bearerToken : "Bearer " + bearerToken;
                request.getHeaders().add("Authorization", token);
            }
            return clientHttpRequestExecution.execute(request, body);
        });
        return restTemplate;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.