如何在Spring Boot中结合生成的客户端Stub使用WS-Security
在Spring Boot中为生成的SOAP客户端Stub配置WS-Security(无需修改生成代码)
1. 选择Maven插件生成客户端Stub
推荐用Apache CXF的cxf-codegen-plugin,它生成的Stub能和Spring无缝集成,且支持配置拦截器。示例Maven配置:
<build> <plugins> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.6.2</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration> <wsdlOptions> <wsdlOption> <wsdl>${project.basedir}/src/main/resources/wsdl/YourService.wsdl</wsdl> <extraargs> <extraarg>-p</extraarg> <extraarg>com.yourpackage.client</extraarg> <extraarg>-client</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
该配置会从指定WSDL生成客户端接口和实现类,存到com.yourpackage.client包下,全程不用手动修改生成代码。
2. 配置WS-Security签名拦截器
创建Spring配置类,定义Wss4jSecurityInterceptor Bean,所有签名参数都可通过配置文件驱动:
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor; @Configuration public class WsSecurityConfig { @Value("${ws.security.key-alias}") private String keyAlias; @Value("${ws.security.keystore-password}") private String keystorePassword; @Value("${ws.security.key-password}") private String keyPassword; @Value("${ws.security.keystore-location}") private String keystoreLocation; @Bean public Wss4jSecurityInterceptor securityInterceptor() { Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor(); // 指定安全动作:添加XML签名 interceptor.setSecurementActions("Signature"); // 密钥库相关配置 interceptor.setSecurementUsername(keyAlias); interceptor.setSecurementPassword(keystorePassword); interceptor.setSecurementKeyPassword(keyPassword); interceptor.setSecurementKeystoreLocation(keystoreLocation); interceptor.setSecurementKeystorePassword(keystorePassword); // 指定要签名的SOAP元素(这里对Body签名) interceptor.setSecurementSignatureParts("{}{http://schemas.xmlsoap.org/soap/envelope/}Body"); return interceptor; } }
对应的application.properties配置:
ws.security.key-alias=your-key-alias ws.security.keystore-password=your-keystore-pass ws.security.key-password=your-key-pass ws.security.keystore-location=classpath:keystore.jks
3. 将拦截器绑定到生成的客户端Stub
通过CXF的JaxWsProxyFactoryBean创建客户端实例,并把拦截器加入其输出拦截器链,完全不用修改生成的Stub代码:
import com.yourpackage.client.YourServicePortType; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SoapClientConfig { private final Wss4jSecurityInterceptor securityInterceptor; public SoapClientConfig(Wss4jSecurityInterceptor securityInterceptor) { this.securityInterceptor = securityInterceptor; } @Bean public YourServicePortType yourServiceClient() { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); // 指定生成的客户端接口 factory.setServiceClass(YourServicePortType.class); // 设置服务端点地址 factory.setAddress("http://your-service-endpoint-url"); // 注入WS-Security拦截器 factory.getOutInterceptors().add(securityInterceptor); return (YourServicePortType) factory.create(); } }
4. 调用测试
在业务代码中直接注入客户端并调用,请求会自动带上签名后的WS-Security头:
import com.yourpackage.client.YourServicePortType; import org.springframework.stereotype.Service; @Service public class BusinessService { private final YourServicePortType soapClient; public BusinessService(YourServicePortType soapClient) { this.soapClient = soapClient; } public void invokeSoapService() { // 直接调用生成的客户端方法,签名逻辑由拦截器自动处理 soapClient.yourServiceMethod(); } }
你可以通过抓包工具(如Wireshark)或开启CXF日志,验证SOAP请求中是否已正确添加带签名的WS-Security头。
内容的提问来源于stack exchange,提问作者Tuomas Toivonen
相关产品推荐
相关产品推荐

