Web Services 在Spring中为WS调用设置SSL和超时(HttpUrlConnectionMessageSender,HttpUrlConnectionMessageSender)

slsn1g29  于 2022-11-15  发布在  Spring
关注(0)|答案(2)|浏览(121)

我正在尝试为WS调用设置超时和SSL(https):

  • PS:不需要标记为重复,唯一相似的question从未被回答过。*

1.我尝试了HttpsUrlConnectionMessageSender,它增加了对(自签名)HTTPS证书的支持,但它确实支持超时。
1.当我切换到支持超时(连接和读取超时)的HttpComponentsMessageSender时,它确实支持SSL。
我想在调用WS时将timeout和ssl合并为:

webServiceTemplate.setDefaultUri(uri);
    response = webServiceTemplate.marshalSendAndReceive(inputs, new SoapHandler(createCredentials(), soapAction));
v8wbuo2f

v8wbuo2f1#

最后,使用HttpComponentsMessageSender完成了它。下面是我的代码:

HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
HttpClient httpClient = HttpClientFactory.getHttpsClient(sslUtils, timeout);
messageSender.setHttpClient(httpClient);
webServiceTemplate.setMessageSender(messageSender);

我还创建了一个新的工厂类HttpClientFactory,用于设置SSL和超时:

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
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;

public class HttpClientFactory {

    private static CloseableHttpClient client;

    private HttpClientFactory() {
    }

    public static HttpClient getHttpsClient(SslUtils sslUtils, int timeout) throws Exception {

        if (client != null) {
            return client;
        }

        SSLContext sslcontext = getSSLContext(sslUtils);
        SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.addInterceptorFirst(new ContentLengthHeaderRemover());
        RequestConfig config = RequestConfig.custom()
                                    .setConnectTimeout(timeout)
                                    .setConnectionRequestTimeout(timeout)
                                    .setSocketTimeout(timeout)
                                    .build();

        return httpClientBuilder.setSSLSocketFactory(factory)
                    .setDefaultRequestConfig(config)
                    .build();
    }

    private static class ContentLengthHeaderRemover implements HttpRequestInterceptor {
        @Override
        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
            request.removeHeaders(HTTP.CONTENT_LEN);
        }
    }

    public static void releaseInstance() {
        client = null;
    }

    private static SSLContext getSSLContext(SslUtils sslUtils) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException {

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(sslUtils.getKeystore().getInputStream(), sslUtils.getKeyPwd().toCharArray());
        sslUtils.getKeystore().getInputStream().close();

        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(sslUtils.getTrustStore().getInputStream(), sslUtils.getTrustPwd().toCharArray());
        sslUtils.getTrustStore().getInputStream().close();

        SSLContextBuilder sslContextBuilder = SSLContexts.custom();
        try {
            sslContextBuilder = SSLContexts.custom().loadKeyMaterial(ks, ssl.getKeyPwd().toCharArray());
        } catch (UnrecoverableKeyException e) {
            e.printStack();
        }
        sslContextBuilder.loadTrustMaterial(ts, new TrustSelfSignedStrategy());
        return sslContextBuilder.build();
    }
}

有关信息,SslUtils只是一个保存密钥库和信任库信息的bean类:

public class SslUtils {

    private Resource keystore;
    private String keyPwd;
    private Resource trustStore;
    private String trustPwd;

    // Getters and Setters
}

这对我很有效,让我同时使用SSL和超时。我希望这对其他人有帮助。

ibps3vxo

ibps3vxo2#

在使用带有基本身份验证的HTTPS协议的情况下,您可能不需要证书,您可以将编码的username:password设置到请求的标头中

package com.james.medici.app.ws;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Base64;

@Slf4j
@Configuration
public class SoapClientConfiguration {

    @Value("${james.medici.url}")
    private String defaultUri;

    @Value("${james.medici.username}")
    private String userName;

    @Value("${james.medici.passcode}")
    private String userPassword;
        
    public static final String SEPARATOR = ":";
    public static final String AUTHORIZATION = "Authorization";
    public static final String BASIC = "Basic ";

    class CustomHttpUrlConnectionMessageSender extends HttpUrlConnectionMessageSender {
        @Override
        protected void prepareConnection(HttpURLConnection connection) throws IOException {
            Base64.Encoder enc = Base64.getEncoder();
            String userpassword = StringUtils.joinWith(SEPARATOR, userName, userPassword);
            String encodedAuthorization = enc.encodeToString(userpassword.getBytes());
            connection.setRequestProperty(AUTHORIZATION, BASIC + encodedAuthorization);
            super.prepareConnection(connection);
        }
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.james.medici.app.ws.model");
        return marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
        log.info(defaultUri);
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(marshaller());
        webServiceTemplate.setUnmarshaller(marshaller());
        webServiceTemplate.setDefaultUri(defaultUri);
        webServiceTemplate.setMessageSender(new CustomHttpUrlConnectionMessageSender());
        return webServiceTemplate;
    } 
}

相关问题