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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21101250/
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 06:35:22  来源:igfitidea点击:

Sending GET request with Authentication headers using restTemplate

javaspringspring-mvcresttemplate

提问by special0ne

I need to retrieve a resources from my server by sending a GET request with the some Authorization headers using RestTemplate.

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

After going over the docsI noticed that none of the GET methods accept headers as a parameter, and the only way to send Headers such as accept and Authorization is by using the exchangemethod.

在查看文档后,我注意到没有一个 GET 方法接受标头作为参数,并且发送诸如接受和授权之类的标头的唯一方法是使用交换方法。

Since it is a very basic action I am wondering if I am missing something and there another, easier way to do it?

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

采纳答案by Sotirios Delimanolis

You're not missing anything. RestTemplate#exchange(..)is the appropriate method to use to set request headers.

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

Here's an example(with POST, but just change that to GET and use the entity you want).

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

Here's another example.

这是另一个例子。

Note that with a GET, your request entity doesn't have to contain anything (unless your API expects it, but that would go against the HTTP spec). It can be an empty String.

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

回答by iwein

You can use postForObjectwith an HttpEntity. It would look like this:

您可以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);

In a GET request, you'd usually not send a body (it's allowed, but it doesn't serve any purpose). The way to add headers without wiring the RestTemplate differently is to use the exchangeor executemethods directly. The get shorthands don't support header modification.

在 GET 请求中,您通常不会发送正文(这是允许的,但没有任何用途)。在不以不同方式连接 RestTemplate 的情况下添加标头的方法是直接使用exchangeorexecute方法。get 简写不支持标题修改。

The asymmetry is a bit weird on a first glance, perhaps this is going to be fixed in future versions of Spring.

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

回答by Dave

Here's a super-simple example with basic authentication, headers, and exception handling...

这是一个带有基本身份验证、标头和异常处理的超级简单示例...

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

回答by ideasculptor

All of these answers appear to be incomplete and/or kludges. Looking at the RestTemplate interface, it sure looks like it is intended to have a ClientHttpRequestFactoryinjected into it, and then that requestFactory will be used to create the request, including any customizations of headers, body, and request params.

所有这些答案似乎都不完整和/或杂乱无章。查看 RestTemplate 接口,它确实看起来像是打算将一个ClientHttpRequestFactory注入其中,然后该 requestFactory 将用于创建请求,包括标头、正文和请求参数的任何自定义。

You either need a universal ClientHttpRequestFactoryto inject into a single shared RestTemplateor else you need to get a new template instance via new RestTemplate(myHttpRequestFactory).

您要么需要一个通用ClientHttpRequestFactory来注入单个共享,RestTemplate要么您需要通过new RestTemplate(myHttpRequestFactory).

Unfortunately, it looks somewhat non-trivial to create such a factory, even when you just want to set a single Authorization header, which is pretty frustrating considering what a common requirement that likely is, but at least it allows easy use if, for example, your Authorization header can be created from data contained in a Spring-Security Authorizationobject, then you can create a factory that sets the outgoing AuthorizationHeader on every request by doing SecurityContextHolder.getContext().getAuthorization()and then populating the header, with null checks as appropriate. Now all outbound rest calls made with that RestTemplate will have the correct Authorization header.

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

Without more emphasis placed on the HttpClientFactory mechanism, providing simple-to-overload base classes for common cases like adding a single header to requests, most of the nice convenience methods of RestTemplateend up being a waste of time, since they can only rarely be used.

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

I'd like to see something simple like this made available

我想看到像这样简单的东西可用

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

At the moment, the interface of the available ClientHttpRequestFactory's are harder to interact with than that. Even better would be an abstract wrapper for existing factory implementations which makes them look like a simpler object like AbstractHeaderRewritingRequestFactory for the purposes of replacing just that one piece of functionality. Right now, they are very general purpose such that even writing those wrappers is a complex piece of research.

目前,可用的 ClientHttpRequestFactory 的接口比这更难与之交互。更好的是现有工厂实现的抽象包装器,这使它们看起来像一个更简单的对象,如 AbstractHeaderRewritingRequestFactory ,目的是替换那一项功能。现在,它们的用途非常广泛,因此即使编写这些包装器也是一项复杂的研究。