如果使用post method spring boot,则对经过身份验证的Rest Web服务的调用失败

时间:2018-08-10 11:31:19

标签: rest web-services spring-boot

我正尝试使用Httpmethod为POST的Spring Boot应用程序中经过认证的其余Web服务,

下面,我想展示所有设置如何工作以使用HttpMethod.GET的身份验证的Web服务,然后进行哪些更改以尝试使用HttpMethod.POST的相同身份验证的Web服务并抛出401未经授权的错误,

RestTemplateFactory获取restTemplte,

   public class RestTemplateFactory implements FactoryBean<RestTemplate>, InitializingBean {

        @Autowired
        private RestTemplate restTemplate;

        public RestTemplate getObject() {
            return restTemplate;
        }
        public Class<RestTemplate> getObjectType() {
            return RestTemplate.class;
        }
        public boolean isSingleton() {
            return true;
        }

        public void afterPropertiesSet() {
            HttpHost host = new HttpHost("localhost", 9090, "http");
            restTemplate = new RestTemplate(
                    new HttpComponentsClientHttpRequestFactoryBasicAuth(host));
        }
    }

对于基本身份验证,

public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpComponentsClientHttpRequestFactory {

        HttpHost host;

        public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) {
            super();
            this.host = host;
        }

        protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
            return createHttpContext();
        }

        private HttpContext createHttpContext() {
            AuthCache authCache = new BasicAuthCache();

            BasicScheme basicAuth = new BasicScheme();
            authCache.put(host, basicAuth);

            BasicHttpContext localcontext = new BasicHttpContext();
            localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
            return localcontext;
        }
    }

为HttpMethod.Get方法调用经过身份验证的Web服务,

 public ResponseEntity<SomeResponse> consumeRestApi(SomeRequest request) throws InvalidDataException {
        ResponseEntity<SomeResponse> responseEntity = null;
        try {
            RestTemplate restTemplate = restTemplateFactory.getRestTemplate();
            restTemplate
                    .getInterceptors()
                    .add(new BasicAuthorizationInterceptor(username, pwd));

            responseEntity = restTemplate.exchange("http://localhost:9090/sendMail?phone=60598745&email=abc@gmail.com", HttpMethod.GET, null, SomeResponse.class);
        } catch (Exception e) {
           // Exception handing...
        }
        return responseEntity;
    }

我确实在虚拟机上使用HttpMethod.Get在本地主机上运行,​​这是我在上述设置中尝试使用的经过身份验证的服务,

@RequestMapping(value = "/sendMail", method = RequestMethod.GET)
public ResponseEntity<SomeResponse> sendmail(@RequestParam String phone, @RequestParam String email){

    SomeResponse response = SomeResponse.builder()
            .id("101")
            .type("formdata")
            .fieldValues(getFieldValues(phone,email))
            .build();

    return new ResponseEntity<>(response,HttpStatus.CREATED);

}

当使用HttpMethod.GET方法时,它可以很好地完成上述所有设置,

现在,我想更改要使用的同一Web服务,以接受HttpMethod.POST

下面是我尝试的更改,但它会返回401错误,即未经授权的错误

我尝试发布方法的更改

通过保持RestTemplateFactoryHttpComponentsClientHttpRequestFactoryBasicAuth相同

我首先更改,虚拟服务器上的其余api接受POST的请求,

@RequestMapping(value = "/sendMail", method = RequestMethod.POST)
    public ResponseEntity<SomeResponse> sendmail(@RequestParam String phone, @RequestParam String email){
// Same as above 
}

下一个更改是使用方法post调用方法

public ResponseEntity<SomeResponse> consumeRestApi(SomeRequest request) throws InvalidDataException {
            ResponseEntity<SomeResponse> responseEntity = null;
            try {
                RestTemplate restTemplate = restTemplateFactory.getRestTemplate();
                restTemplate
                        .getInterceptors()
                        .add(new BasicAuthorizationInterceptor(username, pwd));

                            SomeResponse response = restTemplate.postForObject("http://localhost:9090/sendMail?phone=60598745&email=abc@gmail.com",request, SomeResponse.class);

            } catch (Exception e) {
               // Exception handling....
                }
            }
            return new ResponseEntity<SomeResponse>(HttpStatus.CREATED);
        }

有人对我的错有什么建议吗? 提前致谢。

1 个答案:

答案 0 :(得分:1)

我想问题在于您创建和配置RestTemplate的方式。 Spring Boot提供了RestTemplateBuilder来构建RestTemplate,并且它具有生成器方法来进行其他配置。

此外,RestTemplate是线程安全的,因此可以重新使用创建的实例,而不必重新创建它以使用它。话虽这么说,您的调用类可以重构为这样的东西

public class EndpointTester {

  private final RestTemplate rest;

  public EndpointTester(RestTemplateBuilder rtb, String username, String pwd) {
    this.rest = rtb.basicAuthorization(username, pwd).build();
  }

  public ResponseEntity<SomeResponse> consumeRestApi(SomeRequest request) throws InvalidDataException {
        ResponseEntity<SomeResponse> responseEntity = null;
        try {             
            responseEntity = rest.postForEntity("http://localhost:9090/sendMail?phone=60598745&email=abc@gmail.com", null, SomeResponse.class);
        } catch (Exception e) {
           // Exception handing...
        }
        return responseEntity;
    }
}

这样,您就不需要RestTemplateFactoryHttpComponentsClientHttpRequestFactoryBasicAuth了,从而简化了配置和代码。