Spring WS是否有等效Apache CXF的useReqSigCert配置以用请求证书加密响应
实现方案说明
Spring WS 没有提供与Apache CXF useReqSigCert 完全对应的开箱即用配置项,但可以通过自定义WSS4J安全拦截器的方式实现完全相同的能力:从请求的WS-Security头中提取签名所用的X509证书,再用该证书加密响应的SOAP Body。
核心实现步骤
- 自定义WSS4J安全拦截器,在请求校验阶段提取请求签名携带的BinarySecurityToken(即X509证书),通过ThreadLocal存储避免线程安全问题
- 覆写响应加密逻辑,将提取到的证书作为加密公钥注入加密流程,无需从本地密钥库查询对应证书
- 配置自定义拦截器到Spring WS上下文,启用对应的请求校验和响应加密规则
代码示例
自定义安全拦截器
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor; import org.apache.wss4j.core.WSHandlerResult; import org.apache.wss4j.dom.engine.WSSecurityEngineResult; import org.apache.wss4j.common.ext.WSConstants; import org.springframework.ws.context.MessageContext; import java.security.cert.X509Certificate; public class ReqSigCertBasedEncryptInterceptor extends Wss4jSecurityInterceptor { // 存储当前请求对应的签名证书,线程隔离 private final ThreadLocal<X509Certificate> requestSignatureCertHolder = new ThreadLocal<>(); @Override protected void validateRequest(MessageContext messageContext, Object endpoint) throws Exception { super.validateRequest(messageContext, endpoint); // 从WSS4J请求处理结果中提取签名证书 WSHandlerResult recvResult = (WSHandlerResult) messageContext.getProperty(WSHandlerConstants.RECV_RESULTS); if (recvResult == null) return; for (WSSecurityEngineResult securityResult : recvResult.getResults()) { Integer actionType = (Integer) securityResult.get(WSSecurityEngineResult.TAG_ACTION); if (WSConstants.SIGN == actionType) { X509Certificate sigCert = (X509Certificate) securityResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE); if (sigCert != null) { requestSignatureCertHolder.set(sigCert); break; } } } } @Override protected void secureResponse(MessageContext messageContext, Object endpoint) throws Exception { X509Certificate sigCert = requestSignatureCertHolder.get(); if (sigCert != null) { // 直接使用提取到的证书作为加密公钥 setEncryptionUser(sigCert.getSubjectX500Principal().getName()); setKeyStoreCallbackHandler(callbacks -> { for (Callback cb : callbacks) { if (cb instanceof KeyStoreCallback keyStoreCb) { keyStoreCb.setCertificate(sigCert); } } }); } try { super.secureResponse(messageContext, endpoint); } finally { // 必须清理ThreadLocal,避免线程复用导致的数据混乱 requestSignatureCertHolder.remove(); } } }
拦截器配置(JavaConfig方式)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WsSecurityConfig { @Bean public ReqSigCertBasedEncryptInterceptor wss4jSecurityInterceptor() { ReqSigCertBasedEncryptInterceptor interceptor = new ReqSigCertBasedEncryptInterceptor(); // 配置请求校验规则:验签 + 解密 interceptor.setValidationActions("Signature Encrypt"); interceptor.setValidationSignatureCrypto(yourSignatureVerificationCrypto); interceptor.setValidationDecryptionCrypto(yourRequestDecryptionCrypto); // 配置响应加密规则:仅加密SOAP Body内容 interceptor.setSecurementActions("Encrypt"); interceptor.setSecurementEncryptionParts("{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"); interceptor.setSecurementEncryptionCrypto(yourResponseEncryptionCrypto); return interceptor; } }
注:上述代码中的
yourSignatureVerificationCrypto、yourRequestDecryptionCrypto、yourResponseEncryptionCrypto需要替换为你业务中实际配置的WSS4J Crypto实例。
注意事项
- 请确保请求的WS-Security头中确实携带了明文的BinarySecurityToken,否则会出现证书提取失败的问题,可根据业务需要增加对应的空判断和异常处理逻辑
- 若对安全等级要求较高,可在提取到证书后增加证书信任校验逻辑,确认证书在你的信任域范围内后再用于加密响应
内容的提问来源于stack exchange,提问作者beat
相关产品推荐
相关产品推荐

