You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无Spring依赖的Java SOAP客户端开发:WSDL Policy认证失败问题

解决JAX-WS客户端HTTPS Basic认证+Policy验证失败的问题

我之前处理过类似的场景,结合你的情况,这里有两个不需要依赖Spring或CXF的纯JAX-WS解决方案,能帮你解决None of the policy alternatives can be satisfied的报错:

方案1:手动注入HTTP Basic认证头(简单直接,和SoapUI行为一致)

既然SoapUI仅配置用户名密码就能正常访问,说明服务端实际是基于HTTP Basic Auth做认证的。我们可以通过添加自定义SOAP Handler直接注入认证头,同时绕过Policy的强制校验:

首先创建一个Basic Auth Handler类:

import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.Collections;
import java.util.Set;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class BasicAuthHandler implements SOAPHandler<SOAPMessageContext> {
    private final String username;
    private final String password;

    public BasicAuthHandler(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public Set<QName> getHeaders() {
        return Collections.emptySet();
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (Boolean.TRUE.equals(isOutbound)) {
            // 生成Basic Auth的Base64编码字符串
            String authCredentials = username + ":" + password;
            byte[] encodedAuth = Base64.getEncoder().encode(authCredentials.getBytes(StandardCharsets.UTF_8));
            String authHeader = "Basic " + new String(encodedAuth);
            
            // 添加到HTTP请求头
            context.put(MessageContext.HTTP_REQUEST_HEADERS, 
                        Collections.singletonMap("Authorization", Collections.singletonList(authHeader)));
        }
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    @Override
    public void close(MessageContext context) {
    }
}

然后修改你的客户端代码,添加Handler并关闭Policy校验:

SoapService soapService = new SoapService();
SoapRequest soapRequest = soapService.getSoapRequest();
BindingProvider bindingProvider = (BindingProvider) soapRequest ;
Map<String, Object> requestContext = bindingProvider.getRequestContext();

// 设置请求目标URL
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, connectionUrl);

// 关闭Policy校验(避免因未匹配Policy规则报错)
requestContext.put("com.sun.xml.ws.policy.ignore", true);

// 添加自定义Basic Auth Handler
SOAPBinding binding = (SOAPBinding) bindingProvider.getBinding();
binding.getHandlerChain().add(new BasicAuthHandler(userName, passWord));

// 发起请求
RequestResponse requestResponse = soapRequest.doRequest(request);

方案2:严格遵循WS-SecurityPolicy配置(适合合规要求场景)

如果你需要严格遵循WSDL中的Policy规则,可以通过配置JAX-WS(Metro实现,JDK自带)的安全上下文属性来满足要求:

SoapService soapService = new SoapService();
SoapRequest soapRequest = soapService.getSoapRequest();
BindingProvider bindingProvider = (BindingProvider) soapRequest ;
Map<String, Object> requestContext = bindingProvider.getRequestContext();

requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, connectionUrl);

// 设置Metro专用的安全认证属性
requestContext.put("com.sun.xml.ws.security.auth.username", userName);
requestContext.put("com.sun.xml.ws.security.auth.password", passWord);

// 确保Policy处理启用(默认已启用,可省略)
requestContext.put("com.sun.xml.ws.policy.enable", true);

// 若服务端是自签名证书,需配置信任库
// System.setProperty("javax.net.ssl.trustStore", "/path/to/your/truststore.jks");
// System.setProperty("javax.net.ssl.trustStorePassword", "truststore-password");

RequestResponse requestResponse = soapRequest.doRequest(request);

额外注意事项

  • 如果服务端使用自签名SSL证书,你需要将证书导入Java信任库,或通过代码自定义SSLContext来信任该证书,否则会抛出SSL握手错误。
  • 方案1中的com.sun.xml.ws.policy.ignore是Metro特有的属性,若你使用其他JAX-WS实现(如Apache Axis2),需替换为对应厂商的忽略Policy属性。

内容的提问来源于stack exchange,提问作者T K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 15:42:29