[SPRING] HttpComponentsMessageSender를 사용하여 기본 Auth가있는 WebServiceTemplate
SPRINGHttpComponentsMessageSender를 사용하여 기본 Auth가있는 WebServiceTemplate
아래에 기본 인증으로 보안이 설정된 스프링 웹 서비스를 테스트하려고합니다. 이 테스트에서는 Spring의 WebServiceTemplate 클래스를 사용하여 웹 서비스 클라이언트를 작성했습니다.
템플릿의 MessageSender를 org.apache.commons.httpclient.UsernamePasswordCredentials와 함께 org.springframework.ws.transport.http.CommonsHttpMessageSender 객체 빈으로 생성하면 웹 서비스 클라이언트 호출이 웹 서비스 작업을 제대로 수행 할 수 있습니다. 코드에는 CommonsHttpMessageSender 클래스가 현재 사용되지 않으며 대신 HttpComponentsMessageSender를 사용해야한다는 경고가 강조 표시되어 있습니다.
새로운 HttpComponentsMessageSender 클래스를 사용하여 작동하도록 클라이언트의 WebServiceTemplate을 다시 구성하려고 시도했지만 올바르게 설정된 기본 인증 파트를 가질 수 없습니다. 새로운 HttpComponentsMessageSender 클래스의 경우 org.apache.http.auth.UsernamePasswordCredentials 클래스를 사용하여 자격 증명을 만들었지 만 웹 서비스를 호출하면 자격 증명이 요청과 함께 사용할 수없는 것 같습니다. 요청을 인증하는 데 새로운 클래스를 사용하는 WebServiceTemplate 클라이언트의 작동 예제가 있습니까?
이전의 비추천 클래스를 사용하는 작업 코드가 사용하는 항아리 : commons-httpclient-3.1, spring-ws-core-2.2.0.RELEASE.
새로운 클래스를 가진 나의 작동하지 않는 코드가 사용하는 항아리들 : 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;
}
}
미리 감사드립니다. 오후
해결법
-
==============================
1.UsernamePasswordCredentials와 함께 HttpComponentsMessageSender를 사용하십시오. HttpComponentsMessageSender는 Spring 빈으로 생성해야하며, 수동으로 afterPropertiesSet을 호출하여 http 클라이언트를 올바르게 설정해야합니다. 이 작품은 나를 위해 :
UsernamePasswordCredentials와 함께 HttpComponentsMessageSender를 사용하십시오. HttpComponentsMessageSender는 Spring 빈으로 생성해야하며, 수동으로 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; } }
-
==============================
2.이것은 org.apache.httpcomponents를 사용하여 우리 프로젝트에 대한 운동입니다 : httpclient-4.5.3, httpcore-4.4.6
이것은 org.apache.httpcomponents를 사용하여 우리 프로젝트에 대한 운동입니다 : httpclient-4.5.3, httpcore-4.4.6
우리는 인터셉터 헤더 RequestDefaultHeaders reqHeader = new RequestDefaultHeaders (헤더)를 생성 한 다음 CloseableHttpClient를 빌드 할 때 .addInterceptorLast (reqHeader)를 사용하여 httpClient에 추가합니다.
구성 클래스 :
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; }
-
==============================
3.내가 사용한 한 가지 해결책은 사용자 지정 CredentialsProvider를 사용하여 사용자 지정 WebServiceMessageSender를 만드는 것입니다. 또한이 솔루션은 기본 Java 프록시 설정을 존중하는 라우트 플래너를 설정합니다.
내가 사용한 한 가지 해결책은 사용자 지정 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); } }
-
==============================
4.결국, 현재 httpclient-4.3. +, httpcore-4.3. + 클래스를 사용하여 spring-ws-xxx.2.2.0.RELEASE의 Spring WebServiceTemplate을 사용하여 기본 인증을 작동 시키려면, preemptive 인증 인터셉터를 HttpClient (Apache HttpClient 4의 선점 기본 인증에서 @Oliv가 제안한대로). @Oliv가 지적한 것처럼이 솔루션은 모든 요청에 인증을 추가합니다.
결국, 현재 httpclient-4.3. +, httpcore-4.3. + 클래스를 사용하여 spring-ws-xxx.2.2.0.RELEASE의 Spring WebServiceTemplate을 사용하여 기본 인증을 작동 시키려면, preemptive 인증 인터셉터를 HttpClient (Apache HttpClient 4의 선점 기본 인증에서 @Oliv가 제안한대로). @Oliv가 지적한 것처럼이 솔루션은 모든 요청에 인증을 추가합니다.
Spring WebServiceTemplate을 구성하는 가장 좋은 방법인지 확실하지 않지만 HttpClient의 HttpClientContext 객체에 직접 액세스하지 않고 선점 인증을 사용할 수있는 유일한 방법입니다. 더 간단하고 좋은 답변을드립니다.
인터셉터 코드 :
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); } } }
-
==============================
5.스레드는 오래되었지만 요약입니다.
스레드는 오래되었지만 요약입니다.
스프링 문서에 따라 :
UsernamePasswordCredentials 및 HttpComponentsMessageSender는 스프링 빈이어야합니다. 따라서 빈을 정의하고 삽입하십시오. 문제를 해결해야합니다.
from https://stackoverflow.com/questions/24609751/webservicetemplate-with-basic-auth-using-httpcomponentsmessagesender by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 응용 프로그램 간 Spring Cloud Config Server 공유 등록 정보 (0) | 2019.05.22 |
---|---|
[SPRING] 부트 스트랩 유효성 검사에서 사용자 지정 유효성 검사를 만드는 방법 (0) | 2019.05.22 |
[SPRING] spring : escapeBody 결과 JSON이 잘못되었습니다. (0) | 2019.05.22 |
[SPRING] Spring 구성 클래스에서 생성자 삽입이 가능합니까? (0) | 2019.05.22 |
[SPRING] Spring 재시도와 Retryable 결합 (0) | 2019.05.22 |