JAX-WS - 添加SOAP标头

Jor*_*lan 30 java ws-security soap web-services jax-ws

我正在尝试创建一个独立的客户端来使用一些Web服务.我必须将我的用户名和密码添加到SOAP Header中.我尝试添加凭据如下:

OTSWebSvcsService service = new OTSWebSvcsService();
OTSWebSvcs port = service.getOTSWebSvcs();

BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");

...
Run Code Online (Sandbox Code Playgroud)

当我在服务上调用方法时,我得到以下异常:

com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?我如何将这些属性添加到SOAP标头?

编辑:我使用的是JDK6中包含的JAX-WS 2.1.我现在正在使用JAX-WS 2.2.我现在得到以下异常:

com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5509E: A security token whose type is [http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken] is required.
Run Code Online (Sandbox Code Playgroud)

我该如何创建此令牌?

Evg*_*eny 33

对不起,我的英语不好.可以使用@WebParam(header = true)在SOAP头(JaxWS)中传输数据,如下所示:

@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
@Oneway
public void sendRequest(
    @WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
    Data message,
    @WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
    Header serviceHeader);
Run Code Online (Sandbox Code Playgroud)

如果您想要使用SOAP Headers生成客户端,则需要使用-XadditionalHeaders,如下所示:

wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
Run Code Online (Sandbox Code Playgroud)

如果你不需要@Oneway网络服务,你可以像这样使用Holder:

@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
public void sendRequest(
    @WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
    Data message,
    @WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
    Holder<Header> serviceHeader);
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,`-XadditionalHeaders`是一个重要的属性. (4认同)

Pas*_*ent 27

不是100%肯定,因为问题是缺少一些细节,但如果您使用的是JAX-WS RI,那么请在发送请求时查看添加SOAP标头:

这样做的便携方式是你创建了一个SOAPHandler混乱的SAAJ,但RI提供了一种更好的方法.

创建代理或调度对象时,它们实现 BindingProvider接口.当您使用JAX-WS RI时,您可以向下转换 WSBindingProvider定义仅由JAX-WS RI提供的更多方法.

此接口允许您设置任意数量的Header对象,每个对象代表一个SOAP标头.如果需要,您可以自己实现它,但很可能您使用Headers类中定义的工厂方法 之一来创建一个.

import com.sun.xml.ws.developer.WSBindingProvider;

HelloPort port = helloService.getHelloPort();  // or something like that...
WSBindingProvider bp = (WSBindingProvider)port;

bp.setOutboundHeader(
  // simple string value as a header, like <simpleHeader>stringValue</simpleHeader>
  Headers.create(new QName("simpleHeader"),"stringValue"),
  // create a header from JAXB object
  Headers.create(jaxbContext,myJaxbObject)
);
Run Code Online (Sandbox Code Playgroud)

相应地更新您的代码,然后重试.如果您不使用JAX-WS RI,请更新您的问题并提供更多上下文信息.

更新:您希望调用的Web服务似乎是使用WS-Security/UsernameTokens保护的.这与您最初的问题略有不同.无论如何,要配置您的客户端以发送用户名和密码,我建议查看为基于Metro的Web服务实现WS-Security UsernameToken配置文件的精彩帖子(跳转到第4步).在此步骤中使用NetBeans可能会减轻很多事情.

  • 有关 WS-Security 的帖子链接已失效。 (2认同)

cri*_*oms 7

此外,如果您使用Maven构建项目,则需要添加以下依赖项:

    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>{currentversion}/version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

这为您提供了课程com.sun.xml.ws.developer.WSBindingProvider.

链接:https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt


edu*_*nti 7

我添加这个答案是因为其他人都没有为我工作。

我有一个添加头部处理器代理服务器

import java.util.Set;
import java.util.TreeSet;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPHeaderHandler implements SOAPHandler<SOAPMessageContext> {

    private final String authenticatedToken;

    public SOAPHeaderHandler(String authenticatedToken) {
        this.authenticatedToken = authenticatedToken;
    }

    public boolean handleMessage(SOAPMessageContext context) {
        Boolean outboundProperty =
                (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue()) {
            try {
                SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
                SOAPFactory factory = SOAPFactory.newInstance();
                String prefix = "urn";
                String uri = "urn:xxxx";
                SOAPElement securityElem =
                        factory.createElement("Element", prefix, uri);
                SOAPElement tokenElem =
                        factory.createElement("Element2", prefix, uri);
                tokenElem.addTextNode(authenticatedToken);
                securityElem.addChildElement(tokenElem);
                SOAPHeader header = envelope.addHeader();
                header.addChildElement(securityElem);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // inbound
        }
        return true;
    }

    public Set<QName> getHeaders() {
        return new TreeSet();
    }

    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }

    public void close(MessageContext context) {
        //
    }
}
Run Code Online (Sandbox Code Playgroud)

在代理中,我只添加了处理程序:

BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication;
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken));
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以将用户名和密码添加到 SOAP 标头

BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                "your end point"));
Map<String, List<String>> headers = new HashMap<String, List<String>>();
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
prov.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
Run Code Online (Sandbox Code Playgroud)

  • 如果需要 UsernameToken,这将不起作用 - 这会修改 HTTP 标头,而不是 SOAP 消息标头... (2认同)