JAX-WS - SOAP ヘッダーの追加
-
22-09-2019 - |
質問
いくつかの 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.
このトークンを作成するにはどうすればよいですか?
解決
質問にはいくつかの詳細が欠けているため、100%確実ではありませんが、JAX-WS RIを使用している場合は、以下をご覧ください。 リクエスト送信時のSOAPヘッダーの追加:
これを行うポータブルな方法は、あなたが
SOAPHandler
そして、Saajを台無しにしますが、RIはこれをより良い方法を提供します。プロキシまたはディスパッチオブジェクトを作成すると、それらは実装します
BindingProvider
インターフェース。Jax-WS RIを使用すると、ダウンキャストできますWSBindingProvider
これは、Jax-WS RIによってのみ提供されるいくつかのメソッドを定義します。このインターフェイスを使用すると、任意の数のヘッダーオブジェクトを設定できます。それぞれが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 プロファイルの実装 (ステップ 4 に進みます)。このステップに NetBeans を使用すると、作業が大幅に簡単になる可能性があります。
他のヒント
私の下手な英語でごめんなさい。次のように @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 ヘッダーを含むクライアントを生成したい場合は、次のように -XAdditionalHeaders を使用する必要があります。
wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
@Oneway Web サービスが必要ない場合は、次のように 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);
あなたのプロジェクトをビルドする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する
使用Mavenとプラグイン JAXWS-のMavenプラグイン - に。これは、Webサービスクライアントを生成します。あなたは xadditionalHeaders に設定されていることを確認してくださいtrueに。これは、ヘッダ入力のメソッドを生成します。
他の回答がうまくいかなかったので、この回答を追加しました。
を追加する必要がありました ヘッダーハンドラー に プロキシ:
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ヘッダーにユーザー名とパスワードを追加することができます。
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);
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);
だから、キーMap<String, List<String>>
とRequestContextのからMessageContext.HTTP_REQUEST_HEADERS
は、SOAPヘッダにコピーされます。
ヘッダー経由JAX-WSとアプリケーション認証のサンプル
BindingProvider.USERNAME_PROPERTY
とBindingProvider.PASSWORD_PROPERTY
キーは標準の基本的な許可HttpTransportPipe.addBasicAuth()
ヘッダを付加、Authorization
に特別な方法で処理されます。
私は、Javaコンパイラは結合しないと難しくなってきているパスカルのソリューションに、で始まる、ここではすべての答えに苦労しましたデフォルトではrt.jar
に対して、それ以上(および内部クラスを使用すると、そのランタイム実装に特定します)。
edubriguenti のからの答えは近い私をもたらしました。けれどもハンドラは、コードの最終ビットにフックアップされている方法は、私のために仕事をしませんでした - 。それは呼ばれませんでした。
私は彼のハンドラクラスのバリエーションを使用して終了しますが、このようなjavax.xml.ws.Service
インスタンスにそれを有線ます:
Service service = Service.create(url, qname);
service.setHandlerResolver(
portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs))
);
(私のコースのための)最良のオプションは、それをyourserflを行うことです。それはあなたがprogramattly 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" );
...
私はこのことができます願っています。