JAX-WS - adding SOAP Headers
j'essaie de créer un client autonome pour consommer certains services web. Je dois ajouter mon nom d'utilisateur et mot de passe à L'en-tête SOAP. J'ai essayé d'ajouter les informations d'identification comme suit:
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");
...
Lorsque j'appelle une méthode sur le service que j'ai l'exception suivante:
com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required.
Qu'est-ce que je fais de mal? Comment ajouter ces propriétés à L'en-tête SOAP?
édité: j'utilisais JAX-WS 2.1 inclus dans JDK6. J'utilise maintenant JAX-WS 2.2. Je reçois maintenant la exception suivante:
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.
comment créer ce token?
8 réponses
pas sûr à 100% car la question manque quelques détails mais si vous utilisez JAX-WS RI, alors jetez un oeil à ajouter des en-têtes SOAP lors de l'envoi de requêtes:
la façon portable de faire ceci est que vous créez un
SOAPHandler
et le désordre avec SAAJ, mais le RI fournit une meilleure façon de le faire.lorsque vous créez un mandataire ou une expédition objet, ils mettent en œuvre
BindingProvider
interface. Lorsque vous utilisez le JAX-WS RI, vous pouvez downcast àWSBindingProvider
qui définit une quelques méthodes fournies uniquement par le JAX-WS RI.Cette interface vous permet de définir un nombre arbitraire de l'en-Tête de l'objet, chacune représentant une tête de savon. Vous pouvez la mettre en œuvre sur votre propre si vous vous le voulez, mais vous en utiliseriez probablement un les méthodes d'usine définies sur
Headers
classe pour en créer un.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) );
mettez à jour votre code en conséquence et réessayez. Et si vous n'utilisez pas JAX-WS RI, veuillez mettre à jour votre question et fournir plus d'informations de contexte.
mise à Jour: il semble que le service web que vous voulez appeler est sécurisé avec WS-Security/UsernameTokens. C'est un peu différent de votre question initiale. Quoi qu'il en soit, pour configurer votre client pour envoyer des noms d'utilisateurs et des mots de passe, je suggère de vérifier le Grand post mise en œuvre du profil D'utilisateur de WS-Security Usernametook pour les services web métropolitains (passer à l'étape 4). Utiliser NetBeans pour cette étape pourrait faciliter les choses beaucoup.
Désolé pour mon mauvais anglais. Les données peuvent être transférées dans l'en-tête SOAP (JaxWS) en utilisant @WebParam (header = true) comme ceci:
@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);
Si Vous voulez générer du client avec des en-Têtes SOAP, besoin d'utiliser -XadditionalHeaders comme ça:
wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
Si vous n'avez pas besoin @Oneway service web, vous pouvez utiliser le Titulaire de ce genre:
@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);
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>{currentversion}/version>
</dependency>
cela vous fournit la classe com.sun.xml.ws.developer.WSBindingProvider
.
utilisez maven et le plugin jaxws-maven-plugin. cela générera un client de service web. Assurez-vous que vous êtes réglage de l' xadditionalHeaders pour vrai. Cela générera des méthodes avec des entrées d'en-tête.
j'ajoute cette réponse parce qu'aucun des autres n'a travaillé pour moi.
j'ai dû ajouter un En-Tête 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) {
//
}
}
Dans le proxy, je viens d'ajouter le Gestionnaire:
BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication;
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken));
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
Vous pouvez ajouter le nom d'utilisateur et le mot de passe à L'en-tête 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);
Donc, Map<String, List<String>>
à partir de requestContext avec la touche MessageContext.HTTP_REQUEST_HEADERS
sera copié sur des en-têtes de savon.
Exemple authentification de L'Application avec JAX-WS via des en-têtes
BindingProvider.USERNAME_PROPERTY
et BindingProvider.PASSWORD_PROPERTY
les clés sont traitées de manière spéciale dans HttpTransportPipe.addBasicAuth()
, ajout d'une autorisation de base standard Authorization
en-tête.
Voir aussi Message d'Contexte JAX-WS
j'ai du mal avec toutes les réponses ici, en commençant par la solution de Pascal, qui devient de plus en plus difficile avec le compilateur Java ne se liant pas à rt.jar
par défaut plus (et l'utilisation de classes internes le rend spécifique à cette implémentation d'exécution).
La réponse de edubriguenti m'a amené à proximité. La façon dont le handler est connecté dans le dernier morceau de code n'a pas fonctionné pour moi, bien que - il n'a jamais été appelé.
j'ai fini par utiliser un variation de sa classe de handler, mais il l'a relié dans le javax.xml.ws.Service
exemple comme ceci:
Service service = Service.create(url, qname);
service.setHandlerResolver(
portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs))
);