[英]JAX-WS - Adding SOAP Headers
我正在嘗試創建一個獨立的客戶端來使用一些 Web 服務。 我必須將我的用戶名和密碼添加到 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.
我該如何創建這個令牌?
可以使用@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);
如果要生成帶有 SOAP Header 的客戶端,則需要使用 -XadditionalHeaders:
wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
如果不需要@Oneway web service,可以使用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);
不是 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) );
相應地更新您的代碼並重試。 如果您沒有使用 JAX-WS RI,請更新您的問題並提供更多上下文信息。
更新:您要調用的 Web 服務似乎使用 WS-Security/UsernameTokens 進行保護。 這與您最初的問題有點不同。 無論如何,要將您的客戶端配置為發送用戶名和密碼,我建議查看為基於 Metro 的 Web 服務實現 WS-Security UsernameToken Profile的精彩文章(跳轉到第 4 步)。 在這一步使用 NetBeans 可能會讓事情變得輕松很多。
此外,如果您使用 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
我添加這個答案是因為其他人都沒有為我工作。
我不得不向代理添加一個Header Handler :
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());
您可以將用戶名和密碼添加到 SOAP Header
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);
使用 maven 和插件jaxws-maven-plugin 。 這將生成一個 Web 服務客戶端。 確保將xadditionalHeaders設置為 true。 這將生成帶有標題輸入的方法。
最好的選擇(當然對我來說)是自己動手。 這意味着您可以以編程方式修改 SOAP 消息的所有部分
Binding binding = prov.getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add( new ModifyMessageHandler() );
binding.setHandlerChain( handlerChain );
而 ModifyMessageHandler 源可能是
@Override
public boolean handleMessage( SOAPMessageContext context )
{
SOAPMessage msg = context.getMessage();
try
{
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.addHeader();
SOAPElement ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
...
我希望這可以幫助你
在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);
因此,帶有鍵MessageContext.HTTP_REQUEST_HEADERS
requestContext 中的Map<String, List<String>>
將被復制到 SOAP 標頭。 通過標頭使用 JAX-WS 進行應用程序身份驗證的示例
BindingProvider.USERNAME_PROPERTY
和BindingProvider.PASSWORD_PROPERTY
鍵在HttpTransportPipe.addBasicAuth()
以特殊方式處理,添加了標准的基本授權Authorization
標頭。
另請參閱JAX-WS 中的消息上下文
我在這里掙扎了所有答案,從Pascal 的解決方案開始,隨着 Java 編譯器不再默認綁定rt.jar
(並且使用內部類使其特定於該運行時實現),這變得越來越難。
edubriguenti 的回答讓我很接近。 但是,處理程序在最后一段代碼中的連接方式對我不起作用 - 它從未被調用過。
我最終使用了他的處理程序類的變體,但將其連接到javax.xml.ws.Service
實例中,如下所示:
Service service = Service.create(url, qname); service.setHandlerResolver( portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs)) );
將對象添加到標題我們使用此處使用的示例,但我將完成
ObjectFactory objectFactory = new ObjectFactory();
CabeceraCR cabeceraCR =objectFactory.createCabeceraCR();
cabeceraCR.setUsuario("xxxxx");
cabeceraCR.setClave("xxxxx");
使用對象工廠,我們創建了要求傳遞標頭的對象。 添加到標題的
WSBindingProvider bp = (WSBindingProvider)wsXXXXXXSoap;
bp.setOutboundHeaders(
// Sets a simple string value as a header
Headers.create(jaxbContext,objectFactory.createCabeceraCR(cabeceraCR))
);
我們使用 WSBindingProvider 添加標頭。 直接使用該對象會有一些錯誤,所以我們使用該方法
objectFactory.createCabeceraCR(cabeceraCR)
此方法將在對象工廠上創建一個像這樣的 JAXBElement
@XmlElementDecl(namespace = "http://www.creditreport.ec/", name = "CabeceraCR")
public JAXBElement<CabeceraCR> createCabeceraCR(CabeceraCR value) {
return new JAXBElement<CabeceraCR>(_CabeceraCR_QNAME, CabeceraCR.class, null, value);
}
我們獲得的 jaxbContext 是這樣的:
jaxbContext = (JAXBRIContext) JAXBContext.newInstance(CabeceraCR.class.getPackage().getName());
這會將對象添加到標題中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.