1

我编写了一个接受基本身份验证凭据的 PHP SOAP 服务,如http://www.whitemesa.com/soapauth.html中所述。我通过在实例BasicAuth的处理程序类中定义一个方法来做到这一点。SOAPServer这一切都很好。

但是,当身份验证由于某种原因失败(用户名不正确,BasicAuth请求中没有标头)时,我想BasicChallenge在我的响应中包含一个标头,如下所示:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
      <h:BasicChallenge xmlns:h="http://soap-authentication.org/basic/2001/10/"
                        SOAP-ENV:mustUnderstand="1">
         <Realm>Realm</Realm>
      </h:BasicChallenge>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Client</faultcode>
         <faultstring>Authentication failed</faultstring>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

以下代码不起作用(标头未添加到响应中)。

$soapServer->addSoapHeader(new SoapHeader("http://soap-authentication.org/basic/2001/10/", "BasicChallenge", array("Realm" => "Realm"), true));
throw new SoapFault("Client", "Authentication Failed");

调用$soapServer->fault()而不是throw new SoapFault没有任何区别。

我尝试自己构建 Fault 对象,并将其作为常规响应返回,但我无法让 PHP 发送格式正确的响应。

提前致谢。

4

1 回答 1

0

这是 2013 年,我实际上遇到了完全相同的问题。好吧,现在是 2019 年,PHP 的当前版本是 7.3,而 7.4 正朝着我们迈出一大步。不幸的是,SoapServer 类在 SoapFault 案例中完全忽略了肥皂头。

我编写了一个小变通方法来操作soap 服务器的XML 响应。对于遇到同样问题的每个人,这里有一个小例子,如何解决它。

1. 初始化你的 Soap 服务器

$server = new SoapServer($wsdl, $options);

ob_start();
$server->setObject($service);
$server->handle();
$response = ob_get_contents();
ob_end_clean();

实际上我们正在做一个简单的初始化。我们不是简单地返回内容,而是使用输出缓冲函数拦截 xml 响应。的结果是一个 xml 字符串$response

2. 找出响应是否是故障

实际上SoapServer,如果这是一个有效的响应,该类正在添加肥皂标题。我们必须找出响应是否是错误的。

$doc = new DOMDocument();
$doc->loadXML($response);

$xpath = new DOMXPath($doc);
$isFault = $xpath->query('//*[local-name()="Fault"]')->length;

只需将响应 xml 字符串加载到DOMDocument类中。从现在开始,我们可以使用 DOM 函数访问 xml 元素。为了更好地处理我正在使用DOMXPath该类。当然,也可以使用 DOMDocument 类来确定 XML 节点。该$isFault变量对下一步很有用。

3.在故障情况下设置一个肥皂头

不幸的是,简单地设置一个肥皂头没有花哨addSoapHeader的功能。在这种情况下,我们必须手动完成。

if ($isFault) {
    $header = $doc->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'Header');
    $body = $doc->getElementsByTagNameNS('http://schemas.xmlsoap.org/soap/envelope/', 'Body')->item(0);

    $realm = $doc->createElementNS('http://soap-authentication.org/basic/2001/10/', 'h:Realm');
    $basicChallenge = $doc->createElementNS('http://soap-authentication.org/basic/2001/10/', 'h:BasicChallenge');

    $basicChallenge->appendChild($realm);
    $header->appendChild($basicChallenge);

    $doc->documentElement->insertBefore($header, $body);
}

$xmlResponse = $doc->saveXML($doc->documentElement);

header('Content-Length: ' . strlen($xmlResponse));
echo $xmlResponse;
exit();

在故障情况下,我们创建一个标题元素并添加我们需要的所有子节点。如果附加了所有内容,则在正文之前插入标题,将新的 xml 结构保存在字符串中并回显它。

希望这个对你有帮助。

于 2019-08-27T14:56:40.727 回答