Apache CXF如何为不同SOAP操作指定加密与签名规则
Apache CXF 按SOAP操作差异化配置WSS4J安全规则方案
以下是两种可直接落地的配置方案,无需修改原有WSS4J加解密、签名逻辑:
方案1:自定义路由拦截器(灵活度最高,适合操作数量多、规则可能动态调整的场景)
核心逻辑是先注册一个高优先级的路由拦截器,解析当前请求的SOAP操作名后,动态给需要安全校验的请求绑定WSS4J拦截器。
- 实现自定义路由拦截器:
public class WsSecurityRouteInterceptor extends AbstractPhaseInterceptor<Message> { // 配置需要加密签名的操作本地名集合,可替换为从配置文件读取 private static final Set<String> SECURE_REQUIRED_OPS = Set.of("createOrder", "payOrder", "querySensitiveInfo"); // 预初始化带安全规则的WSS4J拦截器 private final WSS4JStaxInInterceptor secureInInterceptor; private final WSS4JStaxOutInterceptor secureOutInterceptor; public WsSecurityRouteInterceptor() { // 配置为RECEIVE阶段执行,早于WSS4J默认的执行阶段 super(Phase.RECEIVE); // 入站WSS4J配置,和你之前的全局配置逻辑完全一致 Map<String, Object> inProps = new HashMap<>(); inProps.put(ConfigurationConstants.ACTION, "UsernameToken Signature Encrypt"); inProps.put(ConfigurationConstants.SIG_VER_PROP_FILE, "publicKey.properties"); inProps.put(ConfigurationConstants.DEC_PROP_FILE, "privateKey.properties"); secureInInterceptor = new WSS4JStaxInInterceptor(inProps); // 出站WSS4J配置,按需配置响应加密、签名规则 Map<String, Object> outProps = new HashMap<>(); outProps.put(ConfigurationConstants.ACTION, "Signature Encrypt"); outProps.put(ConfigurationConstants.SIG_PROP_FILE, "privateKey.properties"); outProps.put(ConfigurationConstants.ENC_PROP_FILE, "publicKey.properties"); secureOutInterceptor = new WSS4JStaxOutInterceptor(outProps); } @Override public void handleMessage(Message message) throws Fault { BindingOperationInfo operationInfo = message.getExchange().getBindingOperationInfo(); if (operationInfo == null) { return; } String opName = operationInfo.getName().getLocalPart(); // 只有指定操作才加载WSS4J安全拦截器 if (SECURE_REQUIRED_OPS.contains(opName)) { message.getInterceptorChain().add(secureInInterceptor); message.getExchange().getOutMessage().getInterceptorChain().add(secureOutInterceptor); } } }
- 把自定义路由拦截器注册到服务端点:
EndpointImpl endpoint = (EndpointImpl) Endpoint.publish("你的服务地址", new 你的服务实现类()); endpoint.getInInterceptors().add(new WsSecurityRouteInterceptor());
注意不要同时配置全局的WSS4JStaxIn/OutInterceptor,否则所有请求都会默认走安全校验,差异化规则会失效
方案2:操作级绑定拦截器(适合操作数量少、规则固定的场景)
直接给需要安全校验的操作单独绑定WSS4J拦截器,无需额外写路由逻辑:
EndpointImpl endpoint = (EndpointImpl) Endpoint.publish("你的服务地址", new 你的服务实现类()); // 初始化WSS4J入站、出站拦截器,逻辑和方案1一致 WSS4JStaxInInterceptor secureIn = buildSecureInInterceptor(); WSS4JStaxOutInterceptor secureOut = buildSecureOutInterceptor(); // 遍历所有服务操作,给需要安全校验的操作绑定拦截器 for (BindingOperationInfo op : endpoint.getBinding().getBindingInfo().getOperations()) { if (Set.of("createOrder", "payOrder").contains(op.getName().getLocalPart())) { op.getInInterceptors().add(secureIn); op.getOutInterceptors().add(secureOut); } }
额外注意事项
- 如果存在相同本地名、不同命名空间的SOAP操作,匹配时需要加上
operationInfo.getName().getNamespaceURI()的判断,避免误匹配 - 如果你用Spring XML配置CXF端点,可以自定义
BeanPostProcessor在端点初始化完成后执行上述操作绑定逻辑,和Java代码逻辑完全一致
内容的提问来源于stack exchange,提问作者beat
相关产品推荐
相关产品推荐

