gpt4 book ai didi

java - 为什么我的 JAX-WS 处理程序在每个元素上重新声明相同的命名空间?

转载 作者:数据小太阳 更新时间:2023-10-29 02:08:50 26 4
gpt4 key购买 nike

我编写了一个 JAX-WS 处理程序来将 WS-Security header 添加到我的 SOAP 客户端的出站消息中:

package com.soap.client;

import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class ClientHeaderHandler implements SOAPHandler<SOAPMessageContext> {

private static final String WSSECURITY_PREFIX = "wsse";
private static final String WSSECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";

/**
* {@inheritDoc}
* @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
*/
@Override
public boolean handleMessage(final SOAPMessageContext context) {
boolean outbound = false;
outbound = (Boolean) context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);

if (outbound) {
try {
addSecurityHeader(context);
} catch (SOAPException e) {
// do nothing
}
}

return true;
}

private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPElement securityElem = sf.createElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement tokenElem = sf.createElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement usernameElem = sf.createElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
usernameElem.addTextNode("myusername");
tokenElem.addChildElement(usernameElem);

Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement passwordElem = sf.createElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE);
passwordElem.addTextNode("mypassword");

tokenElem.addChildElement(passwordElem);
securityElem.addChildElement(tokenElem);
context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement(securityElem);
}
}

这主要有效;然而,WS-Security 命名空间和前缀在每个使用它们的元素上重新声明 (xmlns:wsse=http://...):

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">myusername</wsse:Username>
<wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">mypassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<MyBody/>
</S:Body>
</S:Envelope>

我已经尝试了 QName、名称等的各种组合,但我似乎无法做到这一点。 我需要更改什么才能仅在最顶层的 Security 元素中声明 WS-Security 命名空间?


更新: gpeche 下面的建议对我有用。从使用 SOAPFactory 创建元素然后通过 addChildElement 附加它到通过 addChildElement 直接创建它:

private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPElement securityElem = context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement tokenElem = securityElem.addChildElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement usernameElem = tokenElem.addChildElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
usernameElem.addTextNode("myusername");

Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement passwordElem = tokenElem.addChildElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE);
passwordElem.addTextNode("mypassword");
}

生成更清晰的 XML:

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>myusername</wsse:Username>
<wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<MyBody/>
</S:Body>
</S:Envelope>

最佳答案

我遇到了同样的问题,我发现唯一可靠的方法是逐个节点地重新生成 XML 树:

  1. 获取对要在其中设置命名空间的节点的引用
  2. 使用所需的前缀、名称、属性和命名空间将子级附加到他的父级。
  3. 递归地将后代复制到新的子代中,调整前缀和命名空间
  4. 完成后,分离原始节点

但是我一直认为一定有更简单的方法...

更新:

好的,我想我知道你的问题是什么:你正在直接从 SOAPFactory 创建所有 SOAPElement。在创建时 SOAPElement 没有父集,因此它们不能继承您从任何人指定的 namespace ,并决定自己编写 namespace 声明。一旦它们被创建,他们就不会费心在 append()/setParent() 时间检查他们是否可以删除任何声明。

您能否尝试仅从 SOAPFactory 创建最外层的元素,然后通过 SOAPElement.addChildElement() 创建其余元素?

关于java - 为什么我的 JAX-WS 处理程序在每个元素上重新声明相同的命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12502003/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com