spring 使用 HttpComponentsMessageSender 的具有基本身份验证的 WebServiceTemplate
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24609751/
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
WebServiceTemplate with Basic Auth using HttpComponentsMessageSender
提问by Going Bananas
I am trying to test a Spring Web Service which is currently secured with Basic Authentication underneath. For these tests, I have written a Web Service client using Spring's WebServiceTemplate
class.
我正在尝试测试当前使用基本身份验证保护的 Spring Web 服务。对于这些测试,我使用 Spring 的WebServiceTemplate
类编写了一个 Web 服务客户端。
My Web Service client calls to the Web Service work okay when I create the template's MessageSender as a org.springframework.ws.transport.http.CommonsHttpMessageSender
object bean with org.apache.commons.httpclient.UsernamePasswordCredentials
and, although the client works, the code has a warning highlighted saying that the CommonsHttpMessageSender
class is now deprecated and that I should be using HttpComponentsMessageSender
instead.
当我创建模板的 MessageSender 作为org.springframework.ws.transport.http.CommonsHttpMessageSender
对象 bean 时org.apache.commons.httpclient.UsernamePasswordCredentials
,我的 Web 服务客户端调用 Web 服务工作正常,尽管客户端工作,但代码突出显示了一个警告,指出CommonsHttpMessageSender
该类现在已弃用,我应该HttpComponentsMessageSender
改用它。
I have tried re-configuring the client's WebServiceTemplate
to work using the newer HttpComponentsMessageSender
class, but I am unable to have the basic auth part configured correctly with it. For the new HttpComponentsMessageSender
class, I have created credentials using the org.apache.http.auth.UsernamePasswordCredentials
class but, when I make a call to the Web Service, the credentials seem to not be available with the request? Is there a working example of a WebServiceTemplate client anywhere that uses these newer classes for authenticating requests, etc?
我尝试重新配置客户端WebServiceTemplate
以使用较新的HttpComponentsMessageSender
类工作,但我无法正确配置基本身份验证部分。对于新HttpComponentsMessageSender
类,我已经使用org.apache.http.auth.UsernamePasswordCredentials
该类创建了凭据,但是,当我调用 Web 服务时,凭据似乎不适用于请求?是否有 WebServiceTemplate 客户端的工作示例使用这些较新的类来验证请求等?
Jars that my working code with old deprecated classes uses: commons-httpclient-3.1
, spring-ws-core-2.2.0.RELEASE
.
我的工作代码与旧的已弃用类使用的罐子:commons-httpclient-3.1
, spring-ws-core-2.2.0.RELEASE
.
Jars that my NON-working code with newer classes uses: httpclient-4.3.4
, httpcore-4.3.2
, spring-ws-core-2.2.0.RELEASE
.
带有较新类的非工作代码使用的罐子:httpclient-4.3.4
, httpcore-4.3.2
, spring-ws-core-2.2.0.RELEASE
.
Test Configuration as it stands for NON-working code:
测试配置,因为它代表非工作代码:
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;
}
}
Thanks in advance, PM
提前致谢,下午
回答by vasekt
Use HttpComponentsMessageSender
with UsernamePasswordCredentials
. Note that HttpComponentsMessageSender
must be created as Spring bean or you must call afterPropertiesSet
manually to be http client correctlly set up.
This works for me:
HttpComponentsMessageSender
与 一起使用UsernamePasswordCredentials
。请注意,HttpComponentsMessageSender
必须创建为 Spring bean 或者您必须afterPropertiesSet
手动调用才能正确设置 http 客户端。这对我有用:
@Configuration
public class WsClientConfiguration {
@Bean
public ESignatureProcessorClient eSignatureProcessorClient() {
ESignatureProcessorClient client = new ESignatureProcessorClient();
client.setWebServiceTemplate(mwWebServiceTemplate());
return client;
}
@Bean
public WebServiceTemplate mwWebServiceTemplate() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("cz.csas.services.esignatureprocessor.v02_02");
WebServiceTemplate template = new WebServiceTemplate(marshaller, marshaller);
template.setDefaultUri("https://osb-st2.vs.csin.cz:5001/CSMW/WS_MW_ESignatureProcessor_v02_02");
template.setMessageSender(defaultMwMessageSender());
return template;
}
@Bean
public HttpComponentsMessageSender defaultMwMessageSender() {
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
messageSender.setCredentials(new UsernamePasswordCredentials("user", "password"));
return messageSender;
}
}
回答by hasto
This is workout for our project using org.apache.httpcomponents
:
httpclient-4.5.3
, httpcore-4.4.6
这是我们项目的锻炼org.apache.httpcomponents
:
httpclient-4.5.3
,httpcore-4.4.6
We create interceptor header RequestDefaultHeaders reqHeader = new RequestDefaultHeaders(headers)
and then add to httpClient using .addInterceptorLast(reqHeader)
when building CloseableHttpClient
我们创建拦截器标头RequestDefaultHeaders reqHeader = new RequestDefaultHeaders(headers)
,然后.addInterceptorLast(reqHeader)
在构建时使用添加到 httpClientCloseableHttpClient
Configuration class :
配置类:
import org.apache.http.message.BasicHeader;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.Header;
import org.apache.http.client.protocol.RequestDefaultHeaders;
@Bean
HttpClient createHttpClient() {
List<Header> headers = new ArrayList<>();
BasicHeader authHeader = new BasicHeader("Authorization", "Basic " + base64authUserPassword());
headers.add(authHeader);
// add more header as more as needed
RequestDefaultHeaders reqHeader = new RequestDefaultHeaders(headers);
CloseableHttpClient httpClient =
HttpClients.custom()
.addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor())
.addInterceptorLast(reqHeader)
.build();
return httpClient;
}
@Bean
public HttpComponentsMessageSender defaultMyMessageSender()
throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(createHttpClient());
//messageSender.setCredentials(credentials());
return messageSender;
}
@Bean
WebServiceTemplate webServiceTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException{
WebServiceTemplate wsTemplate = new WebServiceTemplate();
wsTemplate.setDefaultUri(endpointURI);
wsTemplate.setMessageSender(defaultMyMessageSender());
return wsTemplate;
}
回答by Daniel Seidewitz
One solution I have used is to create a custom WebServiceMessageSender with a custom CredentialsProvider. This solution also sets a route planner that respects the default java proxy settings.
我使用的一种解决方案是使用自定义 CredentialsProvider 创建自定义 WebServiceMessageSender。此解决方案还设置了一个尊重默认 java 代理设置的路由规划器。
@Configuration
public class WebServiceConfiguration {
@Bean
public WebServiceMessageSender webServiceMessageSender(@Value("${endpoint.uri}") endpointUri,
@Value("${endpoint.username}") String username,
@Value("${endpoint.password}") String password) throws Exception {
SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(
ProxySelector.getDefault());
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(endpointUri.getHost(), endpointUri.getPort(), ANY_REALM, ANY_SCHEME), new UsernamePasswordCredentials(username, password););
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor())
.setDefaultCredentialsProvider(credentialsProvider)
.build();
return new HttpComponentsMessageSender(httpclient);
}
}
回答by Prashant Kataria
Thread is old but to summaries.
线程是旧的,但要总结。
As per spring documentation:
根据 spring 文档:
UsernamePasswordCredentials and HttpComponentsMessageSender should be spring beans. So define beans and inject them. It should solve the problem.
UsernamePasswordCredentials 和 HttpComponentsMessageSender 应该是 spring bean。所以定义bean并注入它们。它应该可以解决问题。
回答by Going Bananas
In the end, to make Basic Authentication work with the Spring WebServiceTemplate
in spring-ws-xxx.2.2.0.RELEASE
using current httpclient-4.3.+
, httpcore-4.3.+
classes, I've added a preemptive authentication interceptor to the HttpClient
(as suggested by @Oliv in Preemptive Basic authentication with Apache HttpClient 4). Note that, as pointed out by @Oliv, this solution adds authentication to ALL requests made.
最后,为了使基本身份验证与 SpringWebServiceTemplate
一起spring-ws-xxx.2.2.0.RELEASE
使用当前的httpclient-4.3.+
,httpcore-4.3.+
类,我添加了一个抢占式身份验证拦截器HttpClient
(正如@Oliv 在Preemptive Basic authentication with Apache HttpClient 4 中所建议的那样)。请注意,正如@Oliv 所指出的,此解决方案为所有请求添加了身份验证。
I am still not sure if this is the best way to configure the Spring WebServiceTemplate
but it is the only way I have found (so far) of enabling preemptive authentication without direct access to the HttpClient
's HttpClientContext
object. Any simpler better answers I would very much welcome...
我仍然不确定这是否是配置 Spring 的最佳方式,WebServiceTemplate
但这是我发现(到目前为止)无需直接访问HttpClient
'sHttpClientContext
对象即可启用抢占式身份验证的唯一方式。任何更简单更好的答案我都非常欢迎......
Interceptor code:
拦截器代码:
private static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context)
throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(
HttpClientContext.TARGET_AUTH_STATE);
// If no auth scheme is avaialble yet, initialize it preemptively
if ( authState.getAuthScheme() == null ) {
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
HttpClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(
HttpCoreContext.HTTP_TARGET_HOST);
Credentials creds = credsProvider.getCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if ( creds == null ) {
throw new HttpException("no credentials available for preemptive "
+ "authentication");
}
authState.update(new BasicScheme(), creds);
}
}
}