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: