如何使用SOAP验证用户?
我是否必须要求用户在每个SOAP请求中发送他的用户名和密码,并根据数据库对他进行身份验证?
这不会导致不必要的查询吗?
答案 0 :(得分:9)
更简单的方法是在第一个查询上进行身份验证,在服务器端构建包含远程IP地址的会话记录,以及作为authToken提供给客户端的令牌。然后让客户端在将来的查询中传递此authToken。此authToken必须匹配您保留的有关客户端的内部会话数据,但允许您避免为了进行身份验证而必须往返数据库。
那就是说,@Marcus Adams在无国籍方面有一个很好的观点。有人在那里推各种SOAP security models。 WS-Security是目前最先进的技术。它们都通过将身份验证信息放在SOAP头中来工作 - 毕竟,这就是SOAP消息同时包含头部和bodypart的原因。
答案 1 :(得分:4)
以下是我在标题中如何使用API验证的简单示例:
文件 portfolio-lookup-client.php
<?php
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
class portfolioLookupAuth
{
public $apiKey;
public function __construct($key)
{
$this->apiKey = $key;
}
}
$apiKey = "123456";
$url = 'http://mysite.com/php5soap/portfolio-lookup.wsdl';
$client = new SoapClient($url, array("trace" => 1, "exception" => 0));
// Create the header
$auth = new portfolioLookupAuth($apiKey);
// SoapHeader::__construct ( string $namespace , string $name [, mixed $data [, bool $mustunderstand [, string $actor ]]] )
$header = new SoapHeader($url, "APIValidate", $auth, false);
try {
$result = $client->__soapCall("getPortfolioByName", array("portfolioName" => "WQAM"), NULL, $header);
print_r($result);
print "<pre>\n"; print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n";
print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n"; print "</pre>";
} catch (SoapFault $exception) {
echo 'Exception Thrown: '.$exception->faultstring.'<br><br>';
}
?>
文件 portfolio-lookup-server.php
<?php
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
class PortfolioLookupService {
private $apiKey = '123456';
private $portfolios = array(
'WPOW' => 'Power 96 party station.',
'WQAM' => 'Sports radio site.',
'WJBR' => 'Cool sites for bands.',
'WKIS' => 'Kiss Country 2',
);
public function APIValidate($auth){
if($auth->apiKey != $this->apiKey){
throw new SoapFault("Server", "Incorrect key");
}
}
function getPortfolioByName($portfolioName) {
//print_r($portfolioName); exit();
if (isset($this->portfolios[$portfolioName])) {
return $this->portfolios[$portfolioName];
} else {
return 'Portfolio name "'.$portfolioName.'" not found.';
//throw new SoapFault('code', 'string', 'actor', 'detail', 'name', 'header');
throw new SoapFault("Server","Unknown Name '$portfolioName'.");
}
}
function getPortfoliosAll() {
return $this->portfolios;
}
}
$server = new SoapServer("portfolio-lookup.wsdl");
$server->setClass("PortfolioLookupService");
$server->handle();
?>
文件 portfolio-lookup.wsdl
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='PortfolioLookup'
targetNamespace='http://example.org/PortfolioLookup'
xmlns:tns='PortfolioLookup'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
<message name='getPortfolioByNameRequest'>
<part name='portfolioName' type='xsd:string'/>
</message>
<message name='getPortfolioByNameResponse'>
<part name='Result' type='xsd:string'/>
</message>
<message name='getPortfoliosAllRequest'>
<part name='portfolioName' type='xsd:string'/>
</message>
<message name='getPortfoliosAllResponse'>
<part name='Result' type='xsd:array'/>
</message>
<message name='APIValidateRequest'>
<part name='apiKey' type='xsd:string'/>
</message>
<message name='APIValidateResponse'>
<part name='testReturn' type='xsd:string'/>
</message>
<portType name='PortfolioLookupPortType'>
<operation name='getPortfolioByName'>
<input message='tns:getPortfolioByNameRequest'/>
<output message='tns:getPortfolioByNameResponse'/>
</operation>
<operation name='getPortfoliosAll'>
<input message='tns:getPortfoliosAllRequest'/>
<output message='tns:getPortfoliosAllResponse'/>
</operation>
<operation name='APIValidate'>
<input message='tns:APIValidateRequest'/>
<output message='tns:APIValidateResponse'/>
</operation>
</portType>
<binding name='PortfolioLookupBinding' type='tns:PortfolioLookupPortType'>
<soap:binding style='rpc'
transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='getPortfolioByName'>
<soap:operation soapAction='urn:PortfolioLookup#getPortfolioByName'/>
<input>
<soap:body use='encoded' namespace='urn:PortfolioLookup'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:PortfolioLookup'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
<operation name='getPortfoliosAll'>
<soap:operation soapAction='urn:PortfolioLookup#getPortfoliosAll'/>
<input>
<soap:body use='encoded' namespace='urn:PortfolioLookup'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:PortfolioLookup'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
</binding>
<service name='PortfolioLookupService'>
<port name='PortfolioLookupPort' binding='PortfolioLookupBinding'>
<soap:address location='http://mysite.com/php5soap/portfolio-lookup-server.php'/>
</port>
</service>
</definitions>
答案 2 :(得分:3)
让用户发送每个请求的用户名和密码是我见过的大多数SOAP接口的实现方式。实际上,除了 API密钥之外,我还没有看到任何其他实现,只是交换了其他令牌的用户名和密码。
SOAP接口应该是无状态的,比如HTTP,所以这似乎是正常的结果。
答案 3 :(得分:3)
定义自定义SOAP标头并在标头中交换身份验证凭据。从标题中读取值并进行身份验证。