在Web服务客户端中设置用户名和密码的位置?

时间:2013-01-16 17:43:21

标签: authentication wsdl axis eclipse-wtp wsdl2java

我提供了这个WSDL,我必须为它开发一个客户端(我一直在这里提出问题大声笑)。

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:ManterFornecedor" xmlns:s0="urn:ManterFornecedor" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsdl:types>
    <xsd:schema elementFormDefault="qualified" targetNamespace="urn:ManterFornecedor">
        <xsd:element name="Novo" type="s0:InputMapping1"/>
        <xsd:complexType name="InputMapping1">
            <xsd:sequence>
                <xsd:element name="NO_FORNECEDOR" type="xsd:string"/>
                <xsd:element name="DE_CONTRATO" type="xsd:string"/>
                <xsd:element name="DH_INICIO" nillable="true" type="xsd:dateTime"/>
                <xsd:element name="DH_FIM" nillable="true" type="xsd:dateTime"/>
                <xsd:element name="NO_PRODUTO" type="xsd:string"/>
                <xsd:element name="IC_STATUS" type="s0:IC_STATUSType" nillable="true"/>
            </xsd:sequence>
        </xsd:complexType>
        <xsd:simpleType name="IC_STATUSType">
            <xsd:restriction base="xsd:string">
                <xsd:enumeration value="Ativo"/>
                <xsd:enumeration value="Inativo"/>
            </xsd:restriction>
        </xsd:simpleType>
        <xsd:element name="NovoResponse" type="s0:OutputMapping1"/>
        <xsd:complexType name="OutputMapping1">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:string"/>
        </xsd:sequence>
        </xsd:complexType>
        <xsd:element name="AuthenticationInfo" type="s0:AuthenticationInfo"/>
        <xsd:complexType name="AuthenticationInfo">
        <xsd:sequence>
            <xsd:element name="userName" type="xsd:string"/>
            <xsd:element name="password" type="xsd:string"/>
            <xsd:element minOccurs="0" name="authentication" type="xsd:string"/>
            <xsd:element minOccurs="0" name="locale" type="xsd:string"/>
            <xsd:element minOccurs="0" name="timeZone" type="xsd:string"/>
        </xsd:sequence>
        </xsd:complexType>
    </xsd:schema>
    </wsdl:types>

    <wsdl:message name="NovoSoapOut">
        <wsdl:part element="s0:NovoResponse" name="parameters"></wsdl:part>
    </wsdl:message>

    <wsdl:message name="ARAuthenticate">
        <wsdl:part element="s0:AuthenticationInfo" name="parameters"></wsdl:part>
    </wsdl:message>

    <wsdl:message name="NovoSoapIn">
        <wsdl:part element="s0:Novo" name="parameters"></wsdl:part>
    </wsdl:message>

    <wsdl:portType name="PortPortType">
      <wsdl:operation name="Novo">
        <wsdl:input message="s0:NovoSoapIn"></wsdl:input>
        <wsdl:output message="s0:NovoSoapOut"></wsdl:output>
      </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="PortSoapBinding" type="s0:PortPortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="Novo">
            <soap:operation soapAction="urn:ManterFornecedor/Novo" style="document"/>
            <wsdl:input>
                <soap:header message="s0:ARAuthenticate" part="parameters" use="literal"></soap:header>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="ManterFornecedorService">
        <wsdl:documentation>Fornecedor</wsdl:documentation>
        <wsdl:port binding="s0:PortSoapBinding" name="PortSoap">
            <soap:address location="http://somewhere&amp;webService=ManterFornecedor"/>
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

我提供了完整的WSDL,但问题的重要部分是

    <soap:operation soapAction="urn:ManterFornecedor/Novo" style="document"/>
    <wsdl:input>
        <soap:header message="s0:ARAuthenticate" part="parameters" use="literal"></soap:header>
        <soap:body use="literal"/>
    </wsdl:input>

如您所见,输入的标题中包含ARAuthenticate消息,即

<wsdl:message name="ARAuthenticate">
    <wsdl:part element="s0:AuthenticationInfo" name="parameters"></wsdl:part>
</wsdl:message>

<xsd:element name="AuthenticationInfo" type="s0:AuthenticationInfo"/>
<xsd:complexType name="AuthenticationInfo">
<xsd:sequence>
    <xsd:element name="userName" type="xsd:string"/>
    <xsd:element name="password" type="xsd:string"/>
    <xsd:element minOccurs="0" name="authentication" type="xsd:string"/>
    <xsd:element minOccurs="0" name="locale" type="xsd:string"/>
    <xsd:element minOccurs="0" name="timeZone" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>

我使用Eclipse的Web Services Explorer创建一个WS客户端来测试这个web服务,它运行良好!此客户端具有要设置的用户名和密码字段。

好的,现在我需要使用此客户端示例代码,并实现一个独立(非Web UI)解决方案,该解决方案收集信息并使用客户端将其发送到服务器。但它失败了,我相信这是因为身份验证。

我看到设置的用户名和密码只在PortSoapBindingStub.createCall()中显示:

    org.apache.axis.client.Call _call = super._createCall();
    if (super.maintainSessionSet) {
        _call.setMaintainSession(super.maintainSession);
    }
    if (super.cachedUsername != null) {
        _call.setUsername(super.cachedUsername);
    }
    if (super.cachedPassword != null) {
        _call.setPassword(super.cachedPassword);
    }
    if (super.cachedEndpoint != null) {
        _call.setTargetEndpointAddress(super.cachedEndpoint);
    }
    if (super.cachedTimeout != null) {
        _call.setTimeout(super.cachedTimeout);
    }
    if (super.cachedPortName != null) {
        _call.setPortName(super.cachedPortName);
    }

但是,这些缓存的东西来自哪里?我尝试编辑此代码并手动设置它们,但一直收到错误:

Exception in thread "main" AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
 faultSubcode: 
 faultString: java.lang.ArrayIndexOutOfBoundsException: -1
 faultActor: 
 faultNode: 
 faultDetail: 
    {http://xml.apache.org/axis/}hostname:myhost

java.lang.ArrayIndexOutOfBoundsException: -1
    at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
    at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
    at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(Unknown Source)
    at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
    at org.apache.axis.transport.http.HTTPSender.readFromSocket(HTTPSender.java:796)
    at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:144)
    at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
    at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
    at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
    at org.apache.axis.client.Call.invoke(Call.java:2767)
    at org.apache.axis.client.Call.invoke(Call.java:2443)
    at org.apache.axis.client.Call.invoke(Call.java:2366)
    at org.apache.axis.client.Call.invoke(Call.java:1812)
    at ManterFornecedor.PortSoapBindingStub.novo(PortSoapBindingStub.java:174)
    at ManterFornecedor.PortPortTypeProxy.novo(PortPortTypeProxy.java:50)
    at caixa.pedes.br.ManterFornecedor.main(ManterFornecedor.java:43)

这是我的代码:

import java.net.MalformedURLException;
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Call;

import ManterFornecedor.*;

public class ManterFornecedor {

    public static void main(String[] args) throws RemoteException, ServiceException, MalformedURLException {

        InputMapping1 parameters = new InputMapping1(
                "fornecedor","contrato",java.util.Calendar.getInstance(), java.util.Calendar.getInstance(),
                "produto",IC_STATUSType.Ativo
                );


        java.net.URL endpoint = new java.net.URL("http://somewhere&amp;webService=ManterFornecedor");

        PortPortTypeProxy proxy = new PortPortTypeProxy();

        ManterFornecedorServiceLocator locator = new ManterFornecedorServiceLocator();
        ManterFornecedor.PortPortType port = locator.getPortSoap();

        PortSoapBindingStub client = new PortSoapBindingStub(endpoint,locator);


        ManterFornecedor.OutputMapping1 response = proxy.novo(parameters);

        System.out.println(response);

    }

}

编辑:正如您所看到的,我是Web Service的新手,我有点迷失。我不确切地知道为什么,但是novo()方法在Proxy,Locator和Stub中可用。我会阅读更多有关这些设计模式的内容,因为我也是他们的新手,并且使用所有3个更加麻烦。

用于调用WSDL生成的运算符的最佳对象是什么?不幸的是,在Eclipse中创建的客户端代码使用JSP来接收参数,我无法正确地将例程代码与真实客户端隔离开来,这样我就可以开发代码并调用客户端的操作符。

如果将客户端封装在一个独特的类中,我只需提供其配置(端点,身份验证等),然后调用运算符,这将会容易得多。

2 个答案:

答案 0 :(得分:0)

您必须先将此代码放入setRequestHeaders(_call);

中的PortTypeSoapBindingStub
    try {
        SOAPHeaderElement sopElement = new SOAPHeaderElement("urn:AuthenticationInfo","AuthenticationInfo") ;
        sopElement.addChildElement("userName").addTextNode("XXXXX") ;
        sopElement.addChildElement("password").addTextNode("XXXX");
        sopElement.addChildElement("authentication").addTextNode("");
        sopElement.addChildElement("locale").addTextNode("");
        sopElement.addChildElement("timeZone").addTextNode("");

        _call.addHeader(sopElement);

    } catch (Exception e) {
        e.printStackTrace();
    }

答案 1 :(得分:0)

我也很努力地做到这一点,后来我发现服务器上使用的mac机未启用NTLM身份验证 以下代码对我有用

public static void testNavisionMicrosoft() {
    static String baseURL = "file:C://locapath//customer.wsdl";
    URL url = null;
    try {
        url = new URL(baseURL);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }

    URL url2 = null;
    try {
        url2 = new URL("http://localhost:8080/customer?wsdl");
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }

    try {
        final String username = "user";
        final String password = "paswd";
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password
                        .toCharArray());
            }
        });

        QName qname = new QName("search for soapActionin your wsdl file",
                "search for service name in wsdl file");

        Service service = Service.create(url, qname);
        CRMCustomerPort proxy = service.getPort(CRMCustomerPort.class);
        Map<String, Object> requestContext = ((BindingProvider) proxy)
                .getRequestContext();
        requestContext.put(BindingProvider.USERNAME_PROPERTY, username);
        requestContext.put(BindingProvider.PASSWORD_PROPERTY, password);

        Map<String, List<String>> headers = new HashMap<String, List<String>>();
        headers.put("Timeout", Collections.singletonList("10000"));
        requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);

        CRMCustomer data = proxy.read("AIL0003190");
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(
                "Error occurred in operations web service client initialization",
                e);
    }
}