mardi 1 septembre 2009
J'ai démontré récemment comment créer un service web facilement avec Zend Framework. Cet article pourra servir comme introduction à mon sujet d'aujourd'hui puisque j'expliquerai comment protéger l'accès à un service web en ajoutant une authentification HTTP.
Vous aurez besoin :
- Zend Framework
- un service web
- fichiers .htaccess et .htpasswd
Comme l'authentification HTTP sera réalisée à l'aide de .htaccess et .htpasswd, il sera nécessaire d'indiquer quel fichier protéger dans .htaccess. Les deux actions se trouvant dans le même fichier, il sera nécessaire de les extraire et de séparer le code exitant en deux fichiers. N'oubliez pas que l'URI service.php?wsdl n'existera plus :
- serveur.php
- definition-wsdl.php
Fatal error: Uncaught exception 'SoapFault' with message 'SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://url' : failed to load external entity "http://url" ' in file
C'est parce que le fichier qui génère la définition du WSDL fait aussi la manipulation côté serveur. Par défaut, l'objet AutoDiscover utilise le script courant, sans le paramètre ?wsdl pour trouver l'objet serveur qui prendra en charge la requête ($_SERVER['SCRIPT_NAME']). Dans notre cas, on séparera le script en deux fichiers, le premier créera le wsdl, le second servira à l'objet serveur.
La différence est qu'à la déclaration d'AutoDiscover, on devra assigner à l'objet un autre URI que celui auquel il s'attend par défaut.
Fichier definition-wsdl.php
require_once('Zend/Soap/AutoDiscover.php');Si vous ne définissez pas la ligne $auto->setUri();, vous rencontrerez l'erreur suivante :
require_once('classes/MyClass.php');
$auto = new Zend_Soap_AutoDiscover();
$auto->setClass('MyClass');
// ceci est nouveau!
$auto->setUri('http://url/vers/server.php');
$auto->handle();
Fatal error: Uncaught exception 'SoapFault' with message 'Wrong Version'...
Fichier server.php
require_once('Zend/Soap/Server.php');Fichier .htaccess
require_once('classes/myClass.php');
$server = new Zend_Soap_Server('http://url/vers/definition-wsdl.php');
$server->setClass('MyClass');
$server->handle();
Une fois les fichiers séparés, on peut ajuster .htaccess pour que seul le fichier server.php demande une authentification (plutôt que service.php).
Placez le fichier sur le serveur à la racine du répertoire du service web. Dans .htaccess, indiquez l'emplacement du fichier de mot de passe sous AuthUserFile. Ensuite, protége l'accès au fichier server.php pour qu'il nécessite une authentification.
AuthType BasicFichier .htpasswd
AuthName "Webservice"
AuthUserFile /var/www/emplacement/de/.htpasswd
<files server.php>
Require valid-user
</files>
Vous devrez créer une combinaison login / password à insérer dans .htpasswd. À ce sujet, je vous recommande la lecture de protéger l'accès d'une ressource à l'aide d'un mot de passe. Le mot de passe doit être encrypté en utilisant l'utilitaire de htpasswd.
Fichier client.php
L'objet Zend_Soap_Client permet de spécifier deux paramètres qu'on peut passer en array optionnel pour indiquer le login et le password de l'authentification HTTP lorsque nécessaire.
# $client = new Zend_Soap_Client($wsdl);À ce stade-ci, vous devriez pouvoir accéder au service web protégé. Si l'authentification ne fonctionne pas (par exemple, si vous ne passez pas $options à Zend_Soap_Client ou si les clés d'identification sont erronées), vous verrez une erreur :
# on remplacera l'appel client par ces lignes :
$options = array(
'login' => 'code18',
'password' => '81edoc'
);
$client = new Zend_Soap_Client($wsdl, $options);
$client->votreFonction();
...
Fatal error: Uncaught exception 'SoapFault' with message 'Authorization Required'
Nice,
I was looking for BASIC authorization and Zend_Soap_Client.
Regards
Merci pour partage très instructif !
Voici une version en utilisant les composant MVC du framework :
getRequest()->getActionName() == "server") {
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if ($_SERVER['PHP_AUTH_USER'] != "silverlight" && $_SERVER['PHP_AUTH_PW'] != "silverlight") {
$this->realmAuthenticate();
}
} else {
$this->realmAuthenticate();
}
}
}
public function serverAction ()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
require_once 'Zend/Soap/Server.php';
$server = new Zend_Soap_Server("http://" . $_SERVER['HTTP_HOST'] . BASE_URL . "api/appinterface/wsdl");
$server->setClass($this->className);
$server->handle();
}
public function wsdlAction ()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
require_once 'Zend/Soap/AutoDiscover.php';
$autodiscover = new ZN_Soap_AutoDiscover();
$autodiscover->setClass($this->className);
$autodiscover->setUri("http://" . $_SERVER["HTTP_HOST"] . BASE_URL . "api/appinterface/server");
$autodiscover->handle();
//$autodiscover->handleXSLT("http://" . $_SERVER["HTTP_HOST"] . BASE_URL . "themes/system/wsdl-viewer.xsl");
}
public function realmAuthenticate ()
{
header('WWW-Authenticate: Basic realm="...."');
header('HTTP/1.0 401 Unauthorized');
echo 'Authorization Required.';
exit();
}
}