Android通过WsHttpBinding连接认证WCF服务正常,Java Ksoap2连接失败求助
解决Ksoap2连接带WsHttpBinding+用户名密码认证的WCF服务问题
我之前也踩过这个坑!WsHttpBinding的WCF服务默认启用了WS-Security的UsernameToken验证机制,而Ksoap2框架本身不会自动处理这种安全头,所以必须手动构造对应的SOAP Header才能通过认证。下面是具体的解决步骤和代码示例:
1. 先搞懂WsHttpBinding的认证要求
WsHttpBinding默认要求在SOAP请求的Header里添加符合WS-Security规范的用户名密码节点,大致格式如下:
soapenv:Header
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
wsse:UsernameToken
wsse:Usernameadmin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">adminpass</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
2. 在Ksoap2中手动添加安全Header
你需要修改你的WCFShow方法,手动构造这个安全头并添加到SOAP请求里。这里是修改后的完整示例:
import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapPrimitive; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.ksoap2.HeaderProperty; import java.util.ArrayList; import java.util.List; public static String WCFShow(String METHOD_NAME, int timeOut, List<KSoapParameters> parameters) { // 替换成你实际的WCF服务命名空间和地址 final String NAMESPACE = "http://your-actual-service-namespace/"; final String URL = "http://your-wcf-service-address/MobilService.svc"; final String SOAP_ACTION = NAMESPACE + METHOD_NAME; SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); // 添加传入的参数(如果有) if (parameters != null && !parameters.isEmpty()) { for (KSoapParameters param : parameters) { request.addProperty(param.getKey(), param.getValue()); } } SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.dotNet = true; // 标记为.NET服务,适配WCF的序列化规则 envelope.setOutputSoapObject(request); // 构造WS-Security安全头 List<HeaderProperty> headers = new ArrayList<>(); String securityXml = "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" + "<wsse:UsernameToken>" + "<wsse:Username>admin</wsse:Username>" + "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">adminpass</wsse:Password>" + "</wsse:UsernameToken>" + "</wsse:Security>"; // 添加必要的请求头 headers.add(new HeaderProperty("SOAPAction", SOAP_ACTION)); headers.add(new HeaderProperty("Content-Type", "text/xml;charset=UTF-8")); // 将安全头添加到SOAP信封中 envelope.headerOut = new org.ksoap2.serialization.SoapHeader[]{ new org.ksoap2.serialization.SoapHeader(NAMESPACE, "Security", securityXml) }; HttpTransportSE transport = new HttpTransportSE(URL); transport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); transport.debug = true; // 开启调试,方便查看请求/响应内容 transport.setTimeout(timeOut); try { // 发送请求时传入自定义headers transport.call(SOAP_ACTION, envelope, headers); if (envelope.getResponse() != null) { SoapPrimitive result = (SoapPrimitive) envelope.getResponse(); return result.toString(); } } catch (Exception e) { e.printStackTrace(); // 调试时打印请求和响应内容,方便排查问题 System.out.println("请求内容: " + transport.requestDump); System.out.println("响应内容: " + transport.responseDump); } return null; }
3. 几个关键注意事项
- 替换配置信息:一定要把代码里的
NAMESPACE和URL替换成你WCF服务的实际值,不然肯定连不上。 - SOAP版本适配:如果用
SoapEnvelope.VER11不行,试试SoapEnvelope.VER12,同时把Content-Type改成application/soap+xml;charset=UTF-8——WsHttpBinding有时候会用SOAP 1.2。 - 密码类型匹配:如果你的WCF服务配置了密码哈希(比如
PasswordDigest),那不能直接传明文密码,需要结合nonce和timestamp计算哈希值(这个步骤更复杂,建议先确认服务端的认证配置)。 - 调试技巧:开启
transport.debug = true后,打印transport.requestDump和transport.responseDump,对比Android原生客户端的请求内容,就能快速找到差异点。
内容的提问来源于stack exchange,提问作者Erdinç Ayvaz
相关产品推荐
相关产品推荐

