一部の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ヘッダーを表すヘッダーオブジェクトを任意の数設定できます。必要に応じて独自に実装できますが、ほとんどの場合、ファクトリメソッドの1つを使用します
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 Headersでクライアントを生成する場合、次のような-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
他の誰も私のために働いていないので、私はこの答えを追加しています。
Header HandlerをProxyに追加する必要がありました。
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());
Mavenとプラグイン jaxws-maven-plugin を使用します。これにより、Webサービスクライアントが生成されます。 xadditionalHeaders をtrueに設定していることを確認してください。これにより、ヘッダー入力を持つメソッドが生成されます。
_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
ヘッダーが追加されます。
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)) );
ユーザー名とパスワードを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);
最善のオプション(もちろん私の場合)は、それをyourserflで行うことです。 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" );
...
これがあなたのお役に立てば幸いです