我正在尝试测试一个使用基本身份验证保护的Spring Web服务。为了进行这些测试,我编写了一个Web服务客户端,使用了Spring的WebServiceTemplate
类。
当我将模板的MessageSender创建为一个org.springframework.ws.transport.http.CommonsHttpMessageSender
对象bean,并使用org.apache.commons.httpclient.UsernamePasswordCredentials
时,我的Web服务客户端调用到Web服务是可以正常工作的,尽管客户端可以工作,但代码有一个警告,指出CommonsHttpMessageSender
类现在已经被弃用,我应该使用HttpComponentsMessageSender
替代。
我尝试重新配置客户端的WebServiceTemplate
以使用更新的HttpComponentsMessageSender
类,但我无法正确配置基本认证部分。对于新的HttpComponentsMessageSender
类,我使用org.apache.http.auth.UsernamePasswordCredentials
类创建凭据,但是当我调用Web服务时,凭据似乎无法随请求一起使用?是否有任何使用这些新类进行身份验证请求的WebServiceTemplate客户端的工作示例呢?
我的旧代码与已弃用的类一起使用的jar文件:commons-httpclient-3.1
,spring-ws-core-2.2.0.RELEASE
。
我的新代码与较新的类一起使用的jar文件:httpclient-4.3.4
,httpcore-4.3.2
,spring-ws-core-2.2.0.RELEASE
。
目前,我的非工作代码测试配置如下:
package com.company.service.a.ws.test.config;
import java.io.IOException;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
@PropertySource("classpath:/${environment}-use-case-data.properties")
@ComponentScan(basePackages = "com.company.service.a.ws.test")
@Configuration
public class TestConfig {
@Value("${ws.url}")
private String wsUrl;
@Value("${ws.username}")
private String username;
@Value("${ws.password}")
private String password;
private static final Logger logger = LogManager.getLogger();
@Bean
public SaajSoapMessageFactory messageFactory() {
return new SaajSoapMessageFactory();
}
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.company.service.a.ws.model.data");
return marshaller;
}
@Bean RequestConfig requestConfig() {
RequestConfig requestConfig = RequestConfig.custom()
.setAuthenticationEnabled(true)
.build();
return requestConfig;
}
@Bean
@DependsOn( value = "propertyConfigurer" )
public UsernamePasswordCredentials credentials() {
logger.debug("creating credentials for username: {} passowrd={}",
username, password);
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
username, password);
return credentials;
}
@Bean
public CredentialsProvider credentialsProvider() {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, credentials());
return credentialsProvider;
}
private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{
@Override
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
// fighting org.apache.http.protocol.RequestContent's
// ProtocolException("Content-Length header already present");
request.removeHeaders(HTTP.CONTENT_LEN);
}
}
@Bean
public HttpComponentsMessageSender messageSender() {
RequestConfig requestConfig = RequestConfig.custom()
.setAuthenticationEnabled(true)
.build();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
HttpClient httpClient = httpClientBuilder
.addInterceptorFirst(new ContentLengthHeaderRemover())
.setDefaultRequestConfig(requestConfig)
.setDefaultCredentialsProvider(credentialsProvider())
.build();
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient);
return messageSender;
}
@Bean( name = "propertyConfigurer" )
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
PropertySourcesPlaceholderConfigurer configurer =
new PropertySourcesPlaceholderConfigurer();
return configurer;
}
@Bean
public WebServiceTemplate webServiceTemplate() {
logger.debug("creating webServiceTemplate to url: {}", wsUrl);
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(messageFactory());
webServiceTemplate.setDefaultUri(wsUrl);
webServiceTemplate.setMarshaller(marshaller());
webServiceTemplate.setUnmarshaller(marshaller());
webServiceTemplate.setMessageSender(messageSender());
return webServiceTemplate;
}
}
提前致谢, PM
Object response = webServiceTemplate.marshalSendAndReceive(request);
其中请求只是Web服务的有效负载POJO。 - Going BananasHttpClient
类来设置一个带有添加了AuthCache
的HttpClientContext
,并在调用服务时使用它。是否有示例展示如何为Spring的WebServiceTemplate
设置AuthCache
? - Going BananasHttpClient
,而是在HttpComponentsMessageSender
上设置了凭据,它会处理其余的事情。你可能想要看一下HttpComponentsMessageSender
的源代码。 - M. Deinum