QuickBooks Web 连接器使用 PHP SOAP 服务器进行身份验证

问题描述:

我只是想了解 QBWC 身份验证过程.我正在尝试用 PHP 构建一个真正的基本 SOAP 服务器,它只对 QBWC 请求进行身份验证.

I am just trying to understand the QBWC authenticate process. I am trying to build a real basic SOAP Server in PHP that just authenticates the QBWC requests.

这是我的 WSDL:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://developer.intuit.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://developer.intuit.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">WebService for QBFS created using ASP.NET to troubleshoot QuickBooks WebConnector</wsdl:documentation>
<wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://developer.intuit.com/">
        <s:element name="serverVersion">
            <s:complexType />
        </s:element>
        <s:element name="serverVersionResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="serverVersionResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="clientVersion">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="strVersion" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="clientVersionResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="clientVersionResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="authenticate">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="strUserName" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="strPassword" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="authenticateResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="authenticateResult" type="tns:ArrayOfString" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:complexType name="ArrayOfString">
            <s:sequence>
                <s:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="s:string" />
            </s:sequence>
        </s:complexType>
        <s:element name="connectionError">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="ticket" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="hresult" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="message" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="connectionErrorResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="connectionErrorResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="sendRequestXML">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="ticket" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="strHCPResponse" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="strCompanyFileName" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="qbXMLCountry" type="s:string" />
                    <s:element minOccurs="1" maxOccurs="1" name="qbXMLMajorVers" type="s:int" />
                    <s:element minOccurs="1" maxOccurs="1" name="qbXMLMinorVers" type="s:int" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="sendRequestXMLResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="sendRequestXMLResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="receiveResponseXML">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="ticket" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="response" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="hresult" type="s:string" />
                    <s:element minOccurs="0" maxOccurs="1" name="message" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="receiveResponseXMLResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="1" maxOccurs="1" name="receiveResponseXMLResult" type="s:int" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="getLastError">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="ticket" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="getLastErrorResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="getLastErrorResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="closeConnection">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="ticket" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="closeConnectionResponse">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="closeConnectionResult" type="s:string" />
                </s:sequence>
            </s:complexType>
        </s:element>
    </s:schema>
</wsdl:types>
<wsdl:message name="serverVersionSoapIn">
    <wsdl:part name="parameters" element="tns:serverVersion" />
</wsdl:message>
<wsdl:message name="serverVersionSoapOut">
    <wsdl:part name="parameters" element="tns:serverVersionResponse" />
</wsdl:message>
<wsdl:message name="clientVersionSoapIn">
    <wsdl:part name="parameters" element="tns:clientVersion" />
</wsdl:message>
<wsdl:message name="clientVersionSoapOut">
    <wsdl:part name="parameters" element="tns:clientVersionResponse" />
</wsdl:message>
<wsdl:message name="authenticateSoapIn">
    <wsdl:part name="parameters" element="tns:authenticate" />
</wsdl:message>
<wsdl:message name="authenticateSoapOut">
    <wsdl:part name="parameters" element="tns:authenticateResponse" />
</wsdl:message>
<wsdl:message name="connectionErrorSoapIn">
    <wsdl:part name="parameters" element="tns:connectionError" />
</wsdl:message>
<wsdl:message name="connectionErrorSoapOut">
    <wsdl:part name="parameters" element="tns:connectionErrorResponse" />
</wsdl:message>
<wsdl:message name="sendRequestXMLSoapIn">
    <wsdl:part name="parameters" element="tns:sendRequestXML" />
</wsdl:message>
<wsdl:message name="sendRequestXMLSoapOut">
    <wsdl:part name="parameters" element="tns:sendRequestXMLResponse" />
</wsdl:message>
<wsdl:message name="receiveResponseXMLSoapIn">
    <wsdl:part name="parameters" element="tns:receiveResponseXML" />
</wsdl:message>
<wsdl:message name="receiveResponseXMLSoapOut">
    <wsdl:part name="parameters" element="tns:receiveResponseXMLResponse" />
</wsdl:message>
<wsdl:message name="getLastErrorSoapIn">
    <wsdl:part name="parameters" element="tns:getLastError" />
</wsdl:message>
<wsdl:message name="getLastErrorSoapOut">
    <wsdl:part name="parameters" element="tns:getLastErrorResponse" />
</wsdl:message>
<wsdl:message name="closeConnectionSoapIn">
    <wsdl:part name="parameters" element="tns:closeConnection" />
</wsdl:message>
<wsdl:message name="closeConnectionSoapOut">
    <wsdl:part name="parameters" element="tns:closeConnectionResponse" />
</wsdl:message>
<wsdl:portType name="TroubleshootWebServiceFSSoap">
    <wsdl:operation name="serverVersion">
        <wsdl:input message="tns:serverVersionSoapIn" />
        <wsdl:output message="tns:serverVersionSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="clientVersion">
        <wsdl:input message="tns:clientVersionSoapIn" />
        <wsdl:output message="tns:clientVersionSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="authenticate">
        <wsdl:input message="tns:authenticateSoapIn" />
        <wsdl:output message="tns:authenticateSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="connectionError">
        <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">This web method facilitates web service to handle connection error between QBWC and QB</wsdl:documentation>
        <wsdl:input message="tns:connectionErrorSoapIn" />
        <wsdl:output message="tns:connectionErrorSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="sendRequestXML">
        <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">This web method facilitates web service to send request XML to QuickBooks via QBWebConnector</wsdl:documentation>
        <wsdl:input message="tns:sendRequestXMLSoapIn" />
        <wsdl:output message="tns:sendRequestXMLSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="receiveResponseXML">
        <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">This web method facilitates web service to receive response XML from QuickBooks via QBWebConnector</wsdl:documentation>
        <wsdl:input message="tns:receiveResponseXMLSoapIn" />
        <wsdl:output message="tns:receiveResponseXMLSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="getLastError">
        <wsdl:input message="tns:getLastErrorSoapIn" />
        <wsdl:output message="tns:getLastErrorSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="closeConnection">
        <wsdl:input message="tns:closeConnectionSoapIn" />
        <wsdl:output message="tns:closeConnectionSoapOut" />
    </wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TroubleshootWebServiceFSSoap" type="tns:TroubleshootWebServiceFSSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="serverVersion">
        <soap:operation soapAction="http://developer.intuit.com/serverVersion" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="clientVersion">
        <soap:operation soapAction="http://developer.intuit.com/clientVersion" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="authenticate">
        <soap:operation soapAction="http://developer.intuit.com/authenticate" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="connectionError">
        <soap:operation soapAction="http://developer.intuit.com/connectionError" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="sendRequestXML">
        <soap:operation soapAction="http://developer.intuit.com/sendRequestXML" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="receiveResponseXML">
        <soap:operation soapAction="http://developer.intuit.com/receiveResponseXML" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="getLastError">
        <soap:operation soapAction="http://developer.intuit.com/getLastError" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="closeConnection">
        <soap:operation soapAction="http://developer.intuit.com/closeConnection" style="document" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>
<wsdl:binding name="TroubleshootWebServiceFSSoap12" type="tns:TroubleshootWebServiceFSSoap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="serverVersion">
        <soap12:operation soapAction="http://developer.intuit.com/serverVersion" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="clientVersion">
        <soap12:operation soapAction="http://developer.intuit.com/clientVersion" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="authenticate">
        <soap12:operation soapAction="http://developer.intuit.com/authenticate" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="connectionError">
        <soap12:operation soapAction="http://developer.intuit.com/connectionError" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="sendRequestXML">
        <soap12:operation soapAction="http://developer.intuit.com/sendRequestXML" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="receiveResponseXML">
        <soap12:operation soapAction="http://developer.intuit.com/receiveResponseXML" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="getLastError">
        <soap12:operation soapAction="http://developer.intuit.com/getLastError" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="closeConnection">
        <soap12:operation soapAction="http://developer.intuit.com/closeConnection" style="document" />
        <wsdl:input>
            <soap12:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap12:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>
<wsdl:service name="TroubleshootWebServiceFS">
    <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">WebService for QBFS created using ASP.NET to troubleshoot QuickBooks WebConnector</wsdl:documentation>
    <wsdl:port name="TroubleshootWebServiceFSSoap" binding="tns:TroubleshootWebServiceFSSoap">
        <soap:address location="https://test.developer.intuit.com/QBWC/TroubleshootWebServiceFS/Service.asmx" />
    </wsdl:port>
    <wsdl:port name="TroubleshootWebServiceFSSoap12" binding="tns:TroubleshootWebServiceFSSoap12">
        <soap12:address location="https://test.developer.intuit.com/QBWC/TroubleshootWebServiceFS/Service.asmx" />
    </wsdl:port>
</wsdl:service>

这是我在 PHP 服务器端使用的真正的基本代码:

Here is the real basic code I am using on the PHP Server side:

ini_set( 'soap.wsdl_cache_enabled', '0' );

function authenticate(){

$obj = array(
    '432541432412341234',
    'none',
);

return $obj;

}


$server = new SoapServer('qb.wsdl');
$server->addFunction("authenticate");
$server->handle();

我意识到这实际上并没有检查用户名/密码,但现在我只是想让它对响应进行硬编码.

I realize this does not actually check the username/password but right now I am just trying to get it to work hardcoding the response.

这是我在 QBWC 日志中看到的错误:

Here is the error I see in the QBWC log:

20140328.06:11:13 UTC   : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012:           Authentication failed due to following error message.
Object reference not set to an instance of an object.
More info:
StackTrace =    at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector

我对编写 SOAP 很陌生,所以我可能完全遗漏了一些东西.我只是想通过这个测试更好地理解这个过程.

I am very new to writing SOAP so I could be completely missing something. I just want to understand the process better with this test.

任何帮助都会很棒.

谢谢

我们的经验是,您实际上必须创建一个对象,然后返回该对象.例如:

Our experience has been that you actually have to create an object, and return that. e.g.:

class QuickBooks_WebConnector_Result_Authenticate
{
    public $authenticateResult;

    public function __construct($ticket)
    {
        $this->authenticateResult = array($ticket, 'none');
    }
}
...

function authenticate($object)
{
    return new QuickBooks_WebConnector_Result_Authenticate($ticket);
}

话虽如此 - 您可能想要研究已经存在的解决方案来解决这个问题.Web 连接器协议的实现并非微不足道(尤其是在您还不熟悉 SOAP 的情况下),而且之前已经完成了此操作:

With that said - you might want to look into solutions that already exists to solve this issue. Implementation of the Web Connector protocol is not trivial (especially if you're not already familiar with SOAP), and this has been done before:

这是一个开源 Web 连接器库,可为您处理所有这些 SOAP 内容.这里有一个快速入门指南:

That's an open-source Web Connector library that handles all of this SOAP stuff for you. There's a quick-start guide here:

如果您决定自己动手,这提供了有用的 SOAP 请求/响应,您可以使用它来调试/比较您自己的响应:

If you do decide to go it on your own, this provides helpful SOAP requests/responses you can use for debugging/comparing your own responses to: