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

时间:2014-01-13 21:00:26

标签: java spring spring-mvc resttemplate

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

在查看docs之后,我注意到没有任何GET方法接受标头作为参数,并且发送Headers(如accept和Authorization)的唯一方法是使用exchange方法。 / p>

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

6 个答案:

答案 0 :(得分:56)

你没有遗漏任何东西。 RestTemplate#exchange(..)是用于设置请求标头的适当方法。

Here's an example(使用POST,但只需将其更改为GET并使用您想要的实体)。

Here's another example.

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

答案 1 :(得分:39)

您可以将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进行布线的情况下添加标头的方法是直接使用exchangeexecute方法。 get shorthands不支持标头修改。

乍一看不对称有点奇怪,也许这将在未来的Spring版本中修复。

答案 2 :(得分:17)

这是一个非常简单的示例,包含基本身份验证,标头和异常处理......

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

答案 3 :(得分:7)

所有这些答案似乎都是不完整的和/或kludges。看看RestTemplate接口,它看起来似乎是要注入ClientHttpRequestFactory,然后requestFactory将用于创建请求,包括头,正文和请求参数的任何自定义。

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

不幸的是,创建这样的工厂看起来有点不重要,即使你只是想设置一个Authorization标头,考虑到可能的常见要求,这是非常令人沮丧的,但至少它允许使用方便例如,您的Authorization标头可以从Spring-Security Authorization对象中包含的数据创建,然后您可以创建一个工厂,通过执行SecurityContextHolder.getContext().getAuthorization()在每个请求上设置传出的AuthorizationHeader,然后填充标头,适当时使用空检查。现在,使用该RestTemplate进行的所有出站休息调用都将具有正确的授权标头。

没有更多地强调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,目的是替换这一个功能。现在,它们非常通用,即使编写这些包装也是一项复杂的研究。

答案 4 :(得分:3)

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

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

答案 5 :(得分:0)

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

/**
 * populating the clob;
 */
void populateClob (Clob &clob, int size)
throw (SQLException)
{
Stream *outstream = clob.getStream (1,0);
char *buffer = new char[size];

memset (buffer,'H', size);
outstream->writeBuffer (buffer, size);
char *c = (char *)"";
outstream->writeLastBuffer (c,0);
delete (buffer);
clob.closeStream (outstream);
}

/**
 * printing the clob data as integer stream
 */
void dumpClob (Clob &clob, int size)
throw (SQLException)
{
Stream *instream = clob.getStream (1,0);
char *buffer = new char[size];
memset (buffer, NULL, size);

instream->readBuffer (buffer, size);
cout << "dumping clob: ";
for (int i = 0; i < size; ++i)
  cout << (char) buffer[i];
cout << endl;

delete (buffer);
clob.closeStream (instream);
}