Autor wpisu: Diabl0, dodany: 05.07.2012 01:07, tagi: zend_framework, php
Tym razem poruszę jednocześnie dwie kwestie – tworzenie i obsługę webservices oraz zarządzanie uprawnieniami.
Zanim zaczniemy z autoryzacją i prawami dostępu musimy mieć usługi które udostępniamy. Nie wiem czy wszyscy zdają sobie sprawę że z pomocą ZF w miarę prosto i szybko można za jednym zamachem stworzyć usługi obsługiwane za pomocą trzech najbardziej obecnie popularnych protokołów: XML-RPC, Json-RPC i SOAP.
Stworzymy sobie kontroler do obsługi usług (w moim przypadku main_ServicesController) a w nim 3 metody – każda dla osobnego protokołu.
class main_ServicesController extends Mao_Controller_Action {
/**
*
* Server JSON-RPC
*/
public function jsonAction()
{
$this->disableLayoutAndViews();
$server = new Zend_Json_Server();
$this->_setClasses($server);
if ('GET' == $_SERVER['REQUEST_METHOD']) {
$server
->setTarget( 'http://' . $_SERVER['HTTP_HOST'] . '' . $this->view->url(array('module' => 'main', 'controller' => 'services', 'action' => 'json' )) )
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
header('Content-Type: application/json');
echo $smd;
return;
}
echo $server->handle();
}
/**
*
* Server XML-RPC
*/
public function xmlAction()
{
$this->disableLayoutAndViews();
Zend_XmlRpc_Value::setGenerator(new Zend_XmlRpc_Generator_XmlWriter());
// Specify a cache file
$cacheFile = APPLICATION_PATH . '/temp/xmlrpc.cache';
$server = new Zend_XmlRpc_Server();
// Attempt to retrieve server definition from cache
if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
$this->_setClasses($server);
// Save cache
// @todo: uncomment when going live
//Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
}
echo $server->handle();
}
/**
*
* Server SOAP
*/
public function soapAction() {
$this->disableLayoutAndViews();
$serviceURL = $url = 'http://' . $_SERVER['HTTP_HOST'] . '' . $this->view->url(array('module' => 'main', 'controller' => 'services', 'action' => 'soap' ));
// Generate WSDL relevant to code
if (isset($_GET['wsdl'])){
$autodiscover = new Zend_Soap_AutoDiscover('Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex');
$this->_setClasses($autodiscover);
$autodiscover->handle();
} else {
$server = new Zend_Soap_Server($serviceURL . "?wsdl");
$this->_setClasses($server);
$server->handle();
}
}
/**
* Sets classes for servers
*
* @param object $server
*/
protected function _setClasses( $server ) {
if ( method_exists( $server, 'setClass' ) ) {
$server->setClass( 'main_services_Auth', 'auth' );
$server->setClass( 'shop_services_Products', 'products' );
$server->setClass( 'shop_services_Orders', 'orders' );
}
}
}
Jeden kontroller, 3 akcje, 3 protokoły.
Skoro mamy już zdefiniowane usługi to czas zająć się autoryzacją i uprawnieniami.
Niestety żaden z protokołów nie ma odgórnie ustalonych zasad realizacji tego problemu i w sieci można się spotkać z wieloma sposobami. Ja zamiast każdorazowe przekazywanie pełnych danych logowania zdecydowałem się na tzw. tokeny. Jedna metoda służy do uwierzytelnienia i wystawienia tokena który natomiast jest przekazywany przy wywoływaniu kolejnych metod.
Za logowanie odpowiada klasa:
class main_services_Auth extends main_services_Abstract {
/**
*
* Login and generate login token.
*
* @param string $username username
* @param string $password password
* @param array $additional optional additional informations (currently unused)
*
* @return array dod
*/
public function login( $username, $password, $additional = array() ) {
// 1 - sprawdzamy usera i hasło
$db = Zend_Registry::get ( 'db' );
$authAdapter = new Zend_Auth_Adapter_DbTable ( $db );
$authAdapter->setTableName ( 'users' );
$authAdapter->setIdentityColumn ( 'username' );
$authAdapter->setCredentialColumn ( 'password' );
$authAdapter->setCredentialTreatment('MD5(?) AND active = 1');
// Set the input credential values to authenticate against
$authAdapter->setIdentity ( $username );
$authAdapter->setCredential ( $password );
$auth = Zend_Auth::getInstance ();
$result = $auth->authenticate ( $authAdapter );
if ($result->isValid ()) {
//2 - sprawdzamy/generujemy token
$tokensModel = new main_models_Services_LoginTokens();
$tokenRow = $tokensModel->fetchTokenFor( $username, true );
return array('status' => true, 'token' => $tokenRow->token);
}
return array('status' => false, 'error' => 'Unable to login');
}
}
Jak widać dość typowe zendowska autoryzacja, jedyna różnica to to że po zalogowaniu nie zapisujemy danych użytkownika do Zend_Auth_Storate a jedynie zwracamy token logowania.
Samo generowanie tokena to:
Kanał ATOM
