Java笔记-基于Spring Boot的SOAP双向SSL认证及WS-Security

这里服务端开放了简单的SOAP的API,但是想获取数据时需要双向SSL以及WS-Security签名。

其中对应的xsd文件如下:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://spring.io/guides/gs-producing-web-service"
           targetNamespace="http://spring.io/guides/gs-producing-web-service" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

对应的Maven如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.16.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>3.0.8.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>2.5.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>
                        <source>${project.basedir}/src/main/resources/countries.xsd</source>
                    </sources>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

将源码跑起来(文章最后有源码的打包下载地址)

从中可以看到,HTTPS以及开启

这里使用SoapUI来测试,获取其wsdl

会提示如下错误

下面将证书挂上!

完成后测试下:

可以看到连接成功,获取到了wsdl

 

客户端的配置

客户端中配置主要在SoapConfiguration.java中,首先是配置SSL双向认证:

private static final Resource KEYSTORE_LOCATION = new ClassPathResource("client.jks");
private static final String KEYSTORE_PASSWORD = "keystore";
...

@Bean
Jaxb2Marshaller marshaller() {
   Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
   marshaller.setContextPath("io.spring.guides.gs_producing_web_service");
   return marshaller;
}

@Bean
KeyStoreFactoryBean keyStore() {
   KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
   factoryBean.setLocation(KEYSTORE_LOCATION);
   factoryBean.setPassword(KEYSTORE_PASSWORD);
   return factoryBean;
}

@Bean
TrustManagersFactoryBean trustManagers(KeyStoreFactoryBean keyStore) {
   TrustManagersFactoryBean factoryBean = new TrustManagersFactoryBean();
   factoryBean.setKeyStore(keyStore.getObject());
   return factoryBean;
}

@Bean
HttpsUrlConnectionMessageSender messageSender(
       KeyStoreFactoryBean keyStore,
       TrustManagersFactoryBean trustManagers
) throws Exception {
   HttpsUrlConnectionMessageSender sender = new HttpsUrlConnectionMessageSender();

   KeyManagersFactoryBean keyManagersFactoryBean = new KeyManagersFactoryBean();
   keyManagersFactoryBean.setKeyStore(keyStore.getObject());
   keyManagersFactoryBean.setPassword(KEYSTORE_PASSWORD);
   keyManagersFactoryBean.afterPropertiesSet();

   sender.setKeyManagers(keyManagersFactoryBean.getObject());

   sender.setTrustManagers(trustManagers.getObject());
   return sender;
}

双向SSL认证配置同样也需要在服务端进行设置。在高度安全的环境中客户端都需要有自己的证书,在与服务器通信之前都需要验证这些证书合不合法。

客户端的keystore存放的路径为:src/mian/resources/client.jks。这个jks中包含了客户端的私钥和公钥。使用spring-ws-security配置代替HttpsUrlConnectionMessageSender,使用这种方式可以实现SOAP的双向SSL认证。

下面是配置WS-Security:

@Bean
CryptoFactoryBean cryptoFactoryBean() throws IOException {
   CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
   cryptoFactoryBean.setKeyStoreLocation(KEYSTORE_LOCATION);
   cryptoFactoryBean.setKeyStorePassword(KEYSTORE_PASSWORD);
   return cryptoFactoryBean;
}

@Bean
Wss4jSecurityInterceptor securityInterceptor(CryptoFactoryBean cryptoFactoryBean) throws Exception {
   Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();

   securityInterceptor.setSecurementActions("Signature");
   securityInterceptor.setSecurementUsername(KEY_ALIAS);
   securityInterceptor.setSecurementPassword(KEYSTORE_PASSWORD);

   securityInterceptor.setSecurementSignatureKeyIdentifier("DirectReference");
   securityInterceptor.setSecurementSignatureAlgorithm(WSS4JConstants.RSA_SHA1);
   securityInterceptor.setSecurementSignatureDigestAlgorithm(WSS4JConstants.SHA1);

   securityInterceptor.setSecurementSignatureCrypto(cryptoFactoryBean.getObject());

   return securityInterceptor;
}

这里需要为WSSJ4提供客户端的keystore及password。配置SecurityInterceptor,这个拦截器将每个SOAP消息都带上签名。

最后在GetCountryReponseClient中使用双向SSL及WS-Security:

@Bean
CountryClient countryClient(
       Jaxb2Marshaller marshaller,
       HttpsUrlConnectionMessageSender messageSender,
       Wss4jSecurityInterceptor securityInterceptor
) {
   CountryClient countryClient = new CountryClient();

   countryClient.setInterceptors(new ClientInterceptor[]{securityInterceptor});
   countryClient.setMessageSender(messageSender);

   countryClient.setMarshaller(marshaller);
   countryClient.setUnmarshaller(marshaller);

   return countryClient;
}

下面是测试下客户端,看看连接是否正常以及能否调用服务:

@SpringBootTest
public class CountryClientIntegrationTest {

   @Autowired
   CountryClient countryClient;

   @Test
   void shouldDownloadCountry() {
       // given
       String countryName = "Poland";

       // when
       Country country = countryClient.getCountry(countryName).getCountry();

       // then
       Country expectedCountry = new Country();
       expectedCountry.setName("Poland");
       expectedCountry.setCapital("Warsaw");
       expectedCountry.setCurrency(Currency.PLN);
       expectedCountry.setPopulation(38186860);

       assertThat(country.getName()).isEqualTo("Poland");
       assertThat(country.getCapital()).isEqualTo("Warsaw");
       assertThat(country.getCurrency()).isEqualTo(Currency.PLN);
       assertThat(country.getPopulation()).isEqualTo(38186860);
   }

}

服务端下载地址:

https://github.com/fengfanchen/Java/tree/master/SSLWebService

客户端下载地址:

https://github.com/fengfanchen/Java/tree/master/SSLWebServiceClient

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值