SoapServer 类在 PHP 文档中没有详细记录。 SoapServer 类完全自动地完成您想到的所有事情。您必须使用装饰器类。装饰器是什么以及它的作用我将在接下来的几行中解释。我正在努力推动你朝着正确的方向前进。
不久前,我不得不实现 WSSE 身份验证标准。对于这个例子,我将从 WSSE 标准中提取一些部分。
传入请求的标头看起来像这样...
<soapenv:Header>
<wsse:Security xmlns:wsc="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsc:SecurityContextToken>
<wsc:Identifier>identifier</wsc:Identifier>
</wsc:SecurityContextToken>
</wsse:Security>
</soapenv:Header>
密钥(标识符)标识授权用户执行 Web 服务的功能。从这个意义上说,我们必须在执行任何功能之前检查密钥是否有效。为此,我们需要一个装饰器类,它在实际函数执行之前执行。
class AuthDecorator
{
/**
* Name of the class, which contains the webservice methods
* @var string
*/
protected $class;
/**
* Flag, if the recieved identifier is valid
* @var boolean
*/
protected $isValid = false;
public function getClass() : string
{
return $this->class;
}
public function setClass($class) : AuthDecorator
{
$this->class = $class;
return $this;
}
public function getIsValid() : bool
{
return $this->isValid;
}
public function setIsValid(bool $isValid) : AuthDecorator
{
$this->isValid = $isValid;
return $this;
}
public function __call(string $method, array $arguments)
{
if (!method_exists($this->class, $method)) {
throw new \SoapFault(
'Server',
sprintf(
'The method %s does not exist.',
$method
)
);
}
if (!$this->getIsValid()) {
// return a status object here, wenn identifier is invalid
}
return call_user_func_array(
[ $this->class, $method ],
$arguments
);
}
/**
* Here 's the magic! Method is called automatically with every recieved request
*
* @param object $security Security node form xml request header
*/
public function Security($security) : void
{
// auth against session or database or whatever here
$identifier = $this->getIdentifierFromSomewhereFunc();
if ($security->SecurityContextToken->Identifier == $identfier) {
$this->setIsValid(true);
}
}
}
这就是装饰器类。看起来很简单,嗯?装饰器包含一个类,其名称类似于接收到的请求的 xml 标头的第一个子项。每次我们收到与肥皂服务器的请求时,都会自动执行此方法。除此之外,装饰器检查调用的soap服务器功能是否可用。如果没有引发消费者方的肥皂客户端收到的肥皂故障。如果存在方法也很容易。我们放入一个类中的每个 Web 服务方法。
class SimpleWebservice
{
public function doSomeCoolStuff($withCoolParams) : \SoapVar
{
// do some fancy stuff here and return a SoapVar object as response
}
}
出于说明目的,我们的网络服务只有这一项功能。
但是我们到底是怎么让装饰器与肥皂服务器一起工作的呢?
简单,伙计。 SoapServer 类有一些非常棘手的功能,没有记录。该类有一个名为setObject 的方法。这种方法可以解决问题。
$server = new \SoapServer(
$path_to_wsdl_file,
[
'encoding' => 'UTF-8',
'send_errors' => true,
'soap_version' => SOAP_1_2,
]
);
$decorator = new AuthDecorator();
$decorator->setClass(SimpleWebservice::class);
$server->setObject($decorator);
$server->handle();
这太棒了,对吧?只需初始化SoapServer 类,使用setObject 方法添加装饰器并使用handle 方法运行它。肥皂服务器接收所有请求,在调用 webservice 方法之前,装饰器将检查标识符是否有效。只有当标识符有效时,才会执行被调用的webservice方法。
soap 客户端请求看起来如何?
另一方面,soap 客户端可能看起来像这样......
$client = new SoapClient(
$path_to_wsdl_file,
[
'cache_wsdl' => WSDL_CACHE_NONE,
'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
'exceptions' => true,
'trace' => true,
]
);
$securityContextToken = new \stdClass();
$securityContextToken->Identifier = 'identifier';
$securityContextToken = new \SoapVar(
$securityContextToken,
SOAP_ENC_OBJ,
null,
null,
'SecurityContextToken',
'http://schemas.xmlsoap.org/ws/2005/02/sc'
);
$security = new stdClass();
$security->SecurityContextToken = $securityContextToken;
$security = new \SoapVar(
$security,
SOAP_ENC_OBJ,
null,
null,
'Security',
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
);
$header = new \SoapHeader(
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
'Security',
$security
);
$client->__setSoapHeaders($header);
$result = $client->doSomeCoolStuff(new \SoapParam(...));
结论
在面向对象的上下文中工作时,SoapServer 和 SoapClient 类非常酷。因为文档并没有真正提供关于这两个类的太多信息,所以您必须进行测试和学习。当您知道如何创建 SOAP Web 服务时,您可以轻松地创建它。无需将任何 xml 写入字符串。
在您有效地使用此处看到的代码示例之前,请确保它们只是示例而不是用于生产用途。所示示例应将您推向正确的方向。 ;)
问题?