Объект в заголовке сообщения SOAP интерпретируется как операция

Мне нужно реализовать шлюз в php, который принимает вызовы в SOAP.

WSDL веб-сервиса не очень сложен. Далее я выставляю выдержку того же самого.

<portType name="DeliveryNotification">
    <operation name="notifyDelivery" parameterOrder="parameters platformHeader">
      <input message="tns:notifyDelivery"/>
      <output message="tns:notifyDeliveryResponse"/>
    </operation>
  </portType>
  <binding name="DeliveryNotificationPortBinding" type="tns:DeliveryNotification">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="notifyDelivery">
      <soap:operation soapAction="notifyDelivery"/>
      <input>
        <soap:body use="literal" parts="parameters"/>
        <soap:header message="tns:notifyDelivery" part="platformHeader" use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="DeliveryNotificationService">
    <port name="DeliveryNotificationPortBinding" binding="tns:DeliveryNotificationPortBinding">
      <soap:address location="http://localhost:8888/soapTest/outbound-test.php"/>
    </port>
  </service>

Сценарий, обрабатывающий запрос на выполнение службы, очень прост. Я использую отдельный класс для обработки этой операции и следующего:

$server = new Gateway\Debug\DebugSoapServer(OUTBOUND_API_WSDL, array(
    'soap_version' => SOAP_1_2
));

$server->setObject(new Gateway\Handlers\OutboundHandlerDecorator(new Gateway\Handlers\OutboundHandler()));

try {
    $server->handle();
} catch (Exception $e) {
    $server->fault('Sender', $e->getMessage());
}

OutboundHandlerDecorator будет действовать как прокси для проверки доступа, а затем делегировать конечному обработчику для обработки ответа.

Далее я выставлю свое определение:

class OutboundHandlerDecorator
{
    private $decorated = null;

    public function __construct(OutboundHandler $decorated)
    {
        $this->decorated = $decorated;
    }

    public function __call($method, $params)
    {
        global $methodCalled;

        $methodCalled = $method;

        if (method_exists($this->decorated, $method)) {
            return call_user_func_array(
                array($this->decorated, $method), $params);
        } else {
            throw new \BadMethodCallException();
        }
    }

}

Моя проблема заключается в следующем:

Я создал следующее сообщение SOAP для имитации вызова службы notifyDelivery с помощью инструмента SOAPUI. Далее выставляю результат:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://test.com/">
   <soapenv:Header>
      <ws:platformHeader>
         <platformCredentials>
            <password>myPassword</password>
            <userId>myUser</userId>
         </platformCredentials>
         <platformFlags>
            <retry>1</retry>
         </platformFlags>
      </ws:platformHeader>
   </soapenv:Header>
   <soapenv:Body>
      <ws:notifyDelivery>
         <simId>1234567891234567789</simId>
         <simIdType>ICCID</simIdType>
      </ws:notifyDelivery>
   </soapenv:Body>
</soapenv:Envelope>

В результате я получаю сообщение об ошибке SOAP, потому что выдается исключение BadMethodCallException. Поскольку в первую очередь он пытается найти и выполнить метод с именем " platformHeader ", и для этого нет функции, определенной в классе " OutboundHandler ".

Если я не сгенерирую это исключение, метод notifyDelivery класса OutboundHandler будет выполнен правильно.

Поэтому мой вопрос: почему SoapServer идентифицирует заголовок как операцию? Из SOAPUI я настраиваю заголовок SOAPAction HTTP на "notifyDelivery". Я не понимаю эту операцию.

Как я могу получить доступ к данным заголовка независимо? В переменной $ params у меня есть только данные тела сообщения.

Заранее большое спасибо.

С уважением

1 ответ

Решение

Как вы можете видеть в этом ответе, в обработчике "OutboundHandler" в дополнение к методу для каждой службы, определенной в WSDL, также должен быть метод для каждого заголовка сообщения и определения там логики управления доступом. Вам следует создать метод с именем "platformHeader", и, если учетные данные не верны, выбросить исключение SoapFault. На данный момент я буду реализовывать это таким образом.

class OutboundHandler
{
    /**
     * Validate User Credentials
     * @param $params
     */
    public function platformHeader( $params ){

        if(!($params->platformCredentials->password == "myPassword" && $params->platformCredentials->userId == "myUser"))
            throw new \SoapFault("1", "Incorrect user, request rejected.");
    }

    public function notifyDelivery($params) {

        // do something.

    }

}
Другие вопросы по тегам