Apache WSS4J/CXF下BinarySecurityToken遭XML转义致编码错误求助
解决WS-Security中BinarySecurityToken被XML转义导致的Base64编码错误
嘿,我之前也踩过一模一样的坑!问题根源很明确:你构造SOAP消息时,框架自动把Base64里的特殊字符(比如+、/、=)转成了XML实体(+、/、=),服务器收到的是转义后的字符串,自然不认这是合法的Base64编码。下面给你几个实用的解决思路:
1. 别手动拼XML,用框架安全API构造令牌
这是最稳妥的方式,主流WS框架(比如Apache CXF、Spring WS)都提供了专门的WS-Security API,能自动处理编码和XML转义的问题。举个Apache CXF的实现例子:
// 构造X509类型的BinarySecurityToken BinarySecurityTokenType token = new BinarySecurityTokenType(); token.setValueType("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"); token.setEncodingType("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"); // 直接传入证书字节数组,框架会自动完成Base64编码 token.setValue(Base64.encodeBytes(yourX509Certificate.getEncoded())); // 把令牌加到Security头里 Security securityHeader = new Security(); securityHeader.getAny().add(token); // 最后将Security头添加到SOAP消息中即可
用这种方式生成的令牌,框架会负责正确生成XML元素,绝对不会出现不必要的转义。
2. 手动构造时用DOM元素而非字符串拼接
如果因为对接的WSDL不含安全策略,必须手动构造安全头,别直接拼XML字符串(很容易被框架二次转义),应该把字符串转成DOM Element再添加:
// 先构造包含BinarySecurityToken的XML字符串 String securityXml = "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" + "<wsse:BinarySecurityToken EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" " + "ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" + Base64.encodeBytes(yourCertificateBytes) + "</wsse:BinarySecurityToken>" + "</wsse:Security>"; // 把字符串解析成DOM Element DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); Element securityElement = factory.newDocumentBuilder() .parse(new InputSource(new StringReader(securityXml))) .getDocumentElement(); // 把Element添加到SOAP头 SOAPHeader soapHeader = soapMessage.getSOAPHeader(); soapHeader.addChildElement(securityElement);
通过DOM元素添加,框架会识别这是已经处理好的XML节点,不会再做转义操作。
3. 验证发送的消息内容
最后一定要确认最终发送的SOAP消息是正确的。你可以给WS框架加日志拦截器,打印出发送的原始消息:
比如Apache CXF的配置示例:
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <cxf:bus> <cxf:outInterceptors> <ref bean="loggingOutInterceptor"/> </cxf:outInterceptors> </cxf:bus>
查看日志里的BinarySecurityToken内容,要是能看到原始的+、/而不是转义后的实体,那就说明问题解决了。
核心原则就是:别让XML框架对已经完成Base64编码的内容做二次转义,用框架原生API是最省心的方案。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

