2010-02-24 146 views
27

我想創建一個獨立的客戶端來使用一些Web服務。我必須將我的用戶名和密碼添加到SOAP標題。我嘗試添加憑據如下:JAX-WS - 添加SOAP標頭

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"); 

... 

當我呼籲我的服務得到以下異常的方法:

com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required. 

我在做什麼錯?我將如何將這些屬性添加到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. 

我該如何去創建此令牌?

+0

什麼是您使用的WS棧? – 2010-02-24 01:25:04

+0

JAX-WS 2.1包含在JDK6中。 – 2010-02-24 17:37:51

回答

25

不是100%確定的問題是缺少一些細節,但如果你使用的JAX-WS RI,然後看看Adding SOAP headers when sending requests

這樣做的可移植的方法是, 創建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) 
); 

相應地更新你的代碼,然後再試一次。如果您不使用JAX-WS RI,請更新您的問題並提供更多上下文信息。

更新:看起來您要調用的Web服務是使用WS-Security/UsernameTokens進行保護的。這與你最初的問題有點不同。無論如何,要配置您的客戶端發送用戶名和密碼,我建議檢查偉大的帖子Implementing the WS-Security UsernameToken Profile for Metro-based web services(跳轉到第4步)。使用NetBeans進行此步驟可能會使事情變得非常緩慢。

+1

我無法通過eclipse導入這個'com.sun.xml.internal.ws.developer.WSBindingProvider'類。 – pihentagy 2013-04-23 14:23:03

+0

如果我們使用com.sum包中的類,是否會有任何可移植性問題? – james2611nov 2015-04-14 19:43:33

7

另外,如果你正在使用Maven來構建你的項目,你需要添加下面的依賴關係:

<dependency> 
     <groupId>com.sun.xml.ws</groupId> 
     <artifactId>jaxws-rt</artifactId> 
     <version>{currentversion}/version> 
    </dependency> 

此爲您提供一流的com.sun.xml.ws.developer.WSBindingProvider

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

24

對不起,我的英語不好。數據可以在SOAP頭(JAXWS)通過使用@WebParam(頭=真)一樣,被轉移:

@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); 

,如果你想生成SOAP頭的客戶端,需要使用-XadditionalHeaders這樣的:

wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen 

如果不需要@OneWay Web服務,您可以用持有這樣的:

@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); 
+1

+1,'-XadditionalHeaders'在這種情況下是一個重要的屬性。 – 2013-01-15 14:59:37

+0

header = true爲我做了訣竅。我已經複製了現有的存根,並在maven wsimport的副本上設置了header = true,以便不覆蓋生成的存根。 – Zeus 2015-12-09 19:25:44

+0

-additionalHeader的maven插件中的等價物是什麼? – 2018-03-02 15:54:35

0

我添加了這個答案,因爲沒有其他人爲我工作。

我只好一個頭部處理器添加到代理

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) { 
     // 
    } 
} 

在代理,我剛纔添加的處理程序:

BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication; 
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken)); 
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler()); 
0

jaxws-rt-2.2.10-ources.jar!\com\sun\xml\ws\transport\http\client\HttpTransportPipe.java

public Packet process(Packet request) { 
     Map<String, List<String>> userHeaders = (Map<String, List<String>>) request.invocationProperties.get(MessageContext.HTTP_REQUEST_HEADERS); 
     if (userHeaders != null) { 
      reqHeaders.putAll(userHeaders); 

所以,來自requestContext的Map<String, List<String>>與密鑰MessageContext.HTTP_REQUEST_HEADERS將被複制到SOAP標頭。 樣品Application Authentication with JAX-WS via headers

BindingProvider.USERNAME_PROPERTYBindingProvider.PASSWORD_PROPERTY鍵被處理特殊的方式在HttpTransportPipe.addBasicAuth(),加入標準基本授權Authorization報頭。

又見Message Context in JAX-WS

0

您可以將用戶名和密碼添加到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);