我必须使用PHP实现SOAP Web服务。
我通过使用SoapServer
类来做到这一点,并且一切正常。
我需要为请求使用一种特定的格式:它们必须包含一个带有"Header"
标签的"Authentication"
标签,其中必须使用一个令牌来对执行的客户端进行身份验证请求。
我使用"file_get_contents('php //input')"
来获取我收到的整个请求,然后将其解析以检索所需的令牌。
如果我尝试使用SoapUI模拟SOAP请求,则此方法很好。但是,如果我尝试使用PHP SoapClient进行请求并使用函数SoapHeader
设置标头,则在服务器端"file_get_contents('php //input')"
仅返回整个请求的字段(包含在XML标记中) XML请求)合并成一个字符串,而不是以字符串格式返回整个XML。
我不明白为什么。
答案 0 :(得分:1)
PHP文档中没有很好地记录SoapServer
类。 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服务器的请求时,该方法就会自动执行。装饰者除了检查被调用的soap服务器功能是否可用之外。如果不是,则抛出肥皂故障,表明消费者方的肥皂客户收到了。如果存在一种方法也很容易。我们将每个webservice方法放入一个类中。
class SimpleWebservice
{
public function doSomeCoolStuff($withCoolParams) : \SoapVar
{
// do some fancy stuff here and return a SoapVar object as response
}
}
出于说明目的,我们的Web服务仅具有此功能。
但是我们到底如何将装饰器与soap服务器一起使用?
容易,伙伴。 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方法。
肥皂客户端请求的外观如何?
在另一方面,肥皂客户端看起来像这样...
$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编写为字符串。
在有效率地使用此处显示的代码示例之前,请确保它们仅是示例,并非用于生产用途。所显示的示例应将您推向正确的方向。 ;)
问题?