Spring RestTemplate 收到“401 未经授权”

Spring RestTemplate receives "401 Unauthorized"

我正在使用以下内容通过 Spring 4 中的 RestTemplate 检索 JSON:

protected DocInfoResponse retrieveData(String urlWithAuth) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.add("Authorization", "Basic " + auth.getSig());
    HttpEntity<String> request = new HttpEntity<String>(headers);
    ResponseEntity<DocInfoResponse> response = restTemplate.exchange(urlWithAuth, HttpMethod.GET, request, DocInfoResponse.class);
    return response.getBody();
}

我使用相同的代码(具有不同的响应 class)从同一站点成功获取 JSON 文档(使用不同的参数获取不同的文档)。

当我执行上面的代码时,我收到以下堆栈跟踪(部分):

Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized 
at 
org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]

谁能告诉我为什么这可能会收到异常?

在调查我自己的问题后,我意识到 FireFox RESTClient 是成功的,因为我连接到了目标 URL。我以为我正在使用的基本身份验证毕竟不是那么基本。

最终,我阅读了我尝试连接的应用程序的文档,意识到他们提出了一种连接令牌机制。现在可以了。

阅读你的代码后,我说它看起来还不错,虽然我不确定你调用 getSig.

的对象 auth 是什么

第一件事:尝试从任何客户端访问您的服务,例如网络浏览器、PostMan 或 RESTClient。确保您在未连接到您的应用程序的情况下成功检索您的信息!!!

根据结果,我说你应该尝试手动加密你的 Authorization 令牌(你会很容易在这个网站上找到向你展示如何加密的帖子)或尝试另一种连接机制。

我发现上面最初发布的问题是由于 auth 参数发生了双重加密。我通过使用 UriComponentsBuilder 并在 exchange().

上显式调用 encode() 来解决它
SyncResponse retrieveData(UriComponentsBuilder builder) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
    HttpEntity<String> request = new HttpEntity<String>(headers);
    ResponseEntity<SyncResponse> response = restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET, request, SyncResponse.class);
    return response.getBody();
} 

我的 UriComponentsBuilder 是使用以下方法构建的:

UriComponentsBuilder buildUrl(String urlString) {
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(urlString);

    return auth.appendAuth(builder);
}

auth.appendAuth()urlString 中添加目标服务所需的额外 .queryParams()。)

执行此操作的调用是 retrieveData(buildUrl(urlString));

创建授权 header 的过程对于基本身份验证来说相对简单,因此几乎可以通过几行代码手动完成:

 HttpHeaders createHeaders(String username, String password){
   return new HttpHeaders() {{
         String auth = username + ":" + password;
         byte[] encodedAuth = Base64.encodeBase64( 
            auth.getBytes(Charset.forName("US-ASCII")) );
         String authHeader = "Basic " + new String( encodedAuth );
         set( "Authorization", authHeader );
      }};
}

那么,发送请求就变得如此简单:

RestTemplate restTemplate = new RestTemplate();    
restTemplate.exchange
     (uri, HttpMethod.POST, new HttpEntity<T>(createHeaders(username, password)), clazz);

https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring#manual_auth