Autorização com Zend Framework -	Portal
Autorização é o ato de verificar as permissões de um usuário já autenticado no sistema e, baseando-se nessas permissões, permitir ou bloquear o acesso desse usuário a determinados recursos da aplicação. Se, por exemplo, em um Sistema de Gestão de Conteúdo (CMS), o usuário logado é um escritor, ele poderia ter acesso à escrita de artigos, porém não poderia ter acesso ao cadastro de novos usuários, pode-se obter esse tipo de funcionalidade por meio de um componente de autorização. No Zend Framework, esse componente é o Zend_Acl, que fornece a funcionalidade de Lista de Controle de Acesso (ACL) e gestão de privilégios. Em geral, uma aplicação pode usar essa funcionalidade para controlar o acesso a certos objetos protegidos, requeridos por outros objetos.
$papelMembro = new Zend_Acl_Role('membro');$acl = new Zend_Acl();$acl->addRole($papelMembro);
$papelMembro = new Zend_Acl_Role('membro');$papelColunista = new Zend_Acl_Role('colunista');$acl = new Zend_Acl();$acl->addRole($papelMembro);$acl->addRole($papelColunista, 'membro');
Um recurso é algo a ser protegido, o que pode ser um controlador ou uma ação. Um recurso é encapsulado pela classe Zend_Acl_Resource, que simplesmente armazena o nome do recurso que será protegido. Assim como no caso do Zend_Acl_Role, a classe Zend_Acl_Resource oferece suporte à herança, esta sendo definida no segundo parâmetro do método add() de Zend_Acl. Um exemplo de utilização de recursos é o caso de um sistema de ERP onde usuários do papel "administrador" podem ter acesso ao controlador manutencao, já usuários do papel "operador" podem ter acesso ao controlador produto. Para criar esses recursos, o seguinte código é necessário:
$acl = new Zend_Acl();$acl->addResource(new Zend_Acl_Resource('manutencao'));$acl->addResource(new Zend_Acl_Resource('produto'));
$acl->allow('membro', 'artigos', 'visualizar');$acl->deny('membro', 'artigos', 'adicionar');
if ($acl->isAllowed('member', 'artigos', 'visualizar') {	echo "acesso permitido";}
CREATE TABLE `perfil`( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, nome VARCHAR(30))ENGINE=InnoDB;CREATE TABLE `usuario`( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(30) NOT NULL UNIQUE, senha VARCHAR(60) NOT NULL, nome_completo VARCHAR(100) NOT NULL, perfil_id INT UNSIGNED NOT NULL, FOREIGN KEY(`perfil_id`) REFERENCES `perfil`(`id`) ON UPDATE CASCADE ON DELETE CASCADE)ENGINE=InnoDB;INSERT INTO `perfil`(nome) VALUES ('admin'), ('writer');INSERT INTO `usuario`(login, senha, nome_completo, perfil_id) VALUES ('admin', SHA1('admin'), 'Administrador', 1), ('escritor', SHA1('escritor'), 'Escritor', 2);
autoloaderNamespaces[] = "Aplicacao"resources.frontController.plugins.auth = "Aplicacao_Plugin_Auth"
protected function _initAcl(){	$aclSetup = new Aplicacao_Acl_Setup();}
zf create controller usuarioszf create action adicionar noticiaszf create action adicionar usuarioszf create action forbidden error
<div style="color: #f00;">Você não está autorizado a ver esta página</div>
<?phpclass Aplicacao_Acl_Setup{	/**	 * @var Zend_Acl	 */	protected $_acl;	public function __construct()	{		$this->_acl = new Zend_Acl();		$this->_initialize();	}	protected function _initialize()	{		$this->_setupRoles();		$this->_setupResources();		$this->_setupPrivileges();		$this->_saveAcl();	}	protected function _setupRoles()	{		$this->_acl->addRole( new Zend_Acl_Role('guest') );		$this->_acl->addRole( new Zend_Acl_Role('writer'), 'guest' );		$this->_acl->addRole( new Zend_Acl_Role('admin'), 'writer' );	}	protected function _setupResources()	{		$this->_acl->addResource( new Zend_Acl_Resource('auth') );		$this->_acl->addResource( new Zend_Acl_Resource('error') );		$this->_acl->addResource( new Zend_Acl_Resource('noticias') );		$this->_acl->addResource( new Zend_Acl_Resource('usuarios') );	}	protected function _setupPrivileges()	{		$this->_acl->allow( 'guest', 'auth', array('index', 'login') )				   ->allow( 'guest', 'error', array('error', 'forbidden') );		$this->_acl->allow( 'writer', 'noticias', array('index', 'adicionar') )				   ->allow( 'writer', 'auth', 'logout' );		$this->_acl->allow( 'admin', 'usuarios', array('index', 'adicionar') );	}	protected function _saveAcl()	{		$registry = Zend_Registry::getInstance();		$registry->set('acl', $this->_acl);	}}
<?phpclass Aplicacao_Plugin_Auth extends Zend_Controller_Plugin_Abstract{	/**	 * @var Zend_Auth	 */	protected $_auth = null;	/**	 * @var Zend_Acl	 */	protected $_acl = null;	/**	 * @var array	 */	protected $_notLoggedRoute = array(		'controller' => 'auth',		'action'     => 'login',		'module'     => 'default'	);	/**	 * @var array	 */	protected $_forbiddenRoute = array(		'controller' => 'error',		'action'     => 'forbidden',		'module'     => 'default'	);	public function __construct()	{		$this->_auth = Zend_Auth::getInstance();		$this->_acl = Zend_Registry::get('acl');	}	public function preDispatch(Zend_Controller_Request_Abstract $request)	{		$controller = "";		$action     = "";		$module     = "";		if ( !$this->_auth->hasIdentity() ) {			$controller = $this->_notLoggedRoute['controller'];			$action     = $this->_notLoggedRoute['action'];			$module     = $this->_notLoggedRoute['module'];		} else if ( !$this->_isAuthorized($request->getControllerName(),					$request->getActionName()) ) {			$controller = $this->_forbiddenRoute['controller'];			$action     = $this->_forbiddenRoute['action'];			$module     = $this->_forbiddenRoute['module'];		} else {			$controller = $request->getControllerName();			$action     = $request->getActionName();			$module     = $request->getModuleName();		}		$request->setControllerName($controller);		$request->setActionName($action);		$request->setModuleName($module);	}	protected function _isAuthorized($controller, $action)	{		$this->_acl = Zend_Registry::get('acl');		$user = $this->_auth->getIdentity();		if ( !$this->_acl->has( $controller ) || !$this->_acl->isAllowed( $user, $controller, $action ) )			return false;		return true;	}}
<?phpclass Model_Usuario implements Zend_Acl_Role_Interface{	private $_userName;	private $_roleId;	private $_fullName;	public function getUserName()	{		return $this->_userName;	}	public function setUserName($userName)	{		$this->_userName = (string) $userName;	}	public function getFullName()	{		return $this->_fullName;	}	public function setFullName($fullName)	{		$this->_fullName = (string) $fullName;	}	/**	 *	 */	public function getRoleId()	{		return $this->_roleId;	}	public function setRoleId($roleId)	{		$this->_roleId = (string) $roleId;	}}
<?phpclass Model_Auth{	public static function login($login, $senha)	{		$dbAdapter = Zend_Db_Table::getDefaultAdapter();		//Inicia o adaptador Zend_Auth para banco de dados		$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);		$authAdapter->setTableName('usuario')					->setIdentityColumn('login')					->setCredentialColumn('senha')					->setCredentialTreatment('SHA1(?)');		//Define os dados para processar o login		$authAdapter->setIdentity($login)					->setCredential($senha);		//Faz inner join dos dados do perfil no SELECT do Auth_Adapter		$select = $authAdapter->getDbSelect();		$select->join( array('p' => 'perfil'), 'p.id = usuario.perfil_id', array('nome_perfil' => 'nome') );		//Efetua o login		$auth = Zend_Auth::getInstance();		$result = $auth->authenticate($authAdapter);		//Verifica se o login foi efetuado com sucesso		if ( $result->isValid() ) {			//Recupera o objeto do usuário, sem a senha			$info = $authAdapter->getResultRowObject(null, 'senha');			$usuario = new Model_Usuario();			$usuario->setFullName( $info->nome_completo );			$usuario->setUserName( $info->login );			$usuario->setRoleId( $info->nome_perfil );			$storage = $auth->getStorage();			$storage->write($usuario);			return true;		}		throw new Exception('Nome de usuário ou senha inválida');	}}
<?phpclass AuthController extends Zend_Controller_Action{	public function init()	{	}	public function indexAction()	{		return $this->_helper->redirector('login');	}	public function loginAction()	{		$this->_flashMessenger = $this->_helper->getHelper('FlashMessenger');		$this->view->messages = $this->_flashMessenger->getMessages();		$form = new Form_Login();		$this->view->form = $form;		//Verifica se existem dados de POST		if ( $this->getRequest()->isPost() ) {			$data = $this->getRequest()->getPost();			//Formulário corretamente preenchido?			if ( $form->isValid($data) ) {				$login = $form->getValue('login');				$senha = $form->getValue('senha');				try {					Model_Auth::login($login, $senha);					//Redireciona para o Controller protegido					return $this->_helper->redirector->goToRoute( array('controller' => 'noticias'), null, true);				} catch (Exception $e) {					//Dados inválidos					$this->_helper->FlashMessenger($e->getMessage());					$this->_redirect('/auth/login');				}			} else {				//Formulário preenchido de forma incorreta				$form->populate($data);			}		}	}	public function logoutAction()	{		$auth = Zend_Auth::getInstance();		$auth->clearIdentity();		return $this->_helper->redirector('index');	}}
<h2>Login</h2><?php echo ( sizeof( $this->messages ) > 0 ) ? '<div style="color: #f00;">' . $this->messages[0] . '</div>' : ""; ?><?php echo $this->form; ?>
<h2>Bem-vindo Escritor</h2><a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'logout', 'module' => 'default'), '', true); ?>">	Logout</a>
<h2>Bem-vindo Admin</h2><a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'logout', 'module' => 'default'), '', true); ?>">	Logout</a>
Os componentes do Zend Framework relacionados à autorização apresentam uma API consistente e intuitiva de se utilizar e configurar, o que garante uma baixa curva de aprendizagem para se utilizar as funcionalidades básicas do mesmo. Esses componentes podem ser integrados a todo o processo de despacho da parte MVC do framework através de plugins, o que permite manipular as requisições livremente e, baseado em determinados critérios, redirecionar o usuário para outros pontos da aplicação para informar mensagens de erro ou exigir algum formulário para entrada de dados. O objetivo deste artigo foi demonstrar de forma prática uma maneira de implementar autorização e integrá-la ao MVC, porém, vale ressaltar, que existem diversas formas de se chegar a essa funcionalidade. Para maiores informações, a seção de referências logo abaixo pode ser de grande valia. No próximo artigo, os componentes de Internacionalização e Localização serão abordados, até lá!
Deixe um comentário! Cancelar resposta47 O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *Comentando como Anônimo
Wordpress Hashcash needs javascript to work, but your browser has javascript disabled. Your comment will be queued in Akismet!	Flavio Ferreira disse:	3 de setembro de 2010 às 14:42	Parabéns pelo Artigo muito didático.
Responder	Fernando Geraldo Mantoan disse:	25 de julho de 2012 às 14:33	Obrigado Flavio
Responder	disse:	4 de setembro de 2010 às 16:17	Bacana o artigo… parabéns!
Responder	Fernando Geraldo Mantoan disse:	25 de julho de 2012 às 14:33	Obrigado Daniel
Responder	disse:	8 de setembro de 2010 às 17:52	Woow!! Parabéns pelo artigo!!
Responder	Fernando Geraldo Mantoan disse:	25 de julho de 2012 às 14:33	Obrigado Leonardo
Responder	disse:	13 de setembro de 2010 às 11:28	Implementei seu primeiro artigo e deu tudo certo, mas neste segundo está dando um erro, já tentei verificar mas não consigo encontrar, o php me tras este erro:
Catchable fatal error: Object of class Application_Model_Usuario could not be converted to string in D:\server\testeZend\library\Zend\Acl\Role\Registry.php on line 124 0
Responder	Fernando Geraldo Mantoan disse:	13 de setembro de 2010 às 14:06	Estranho, está implementando Zend_Acl_Role_Interface? Provavelmente seu Model não implementou a interface e ele tentou utilizar a role como string por isso deu erro. Att.
Responder	valmir disse:	6 de julho de 2011 às 17:07	cara no meu caso foi mais simples, provalvelmente vc esta logadao, e por isso deus os erros, desative o plugin e faça um logout, que ira ocorrer tudo certo
Responder	disse:	13 de setembro de 2010 às 18:15	Obrigado por responder, estou meio perdido com o zend ainda, realmente não estava implementando a interface, agora está funcionando mas está indo só para a tela escritor, não redireciona a admin, o que será, outra coisa, o sistema só funciona se colocar "Application_" antes do nome dado, como na classe "Model_Auth" que tem de ser "Application_Model_Auth", e em vários outros locais do código onde você se refere a um arquivo que se encontra dentro de application, obrigado.
Responder	Fernando Geraldo Mantoan disse:	13 de setembro de 2010 às 19:54	Olá, bom este comportamento de ir para a tela escritor é normal, já que a rota retornada em loginAction está apontando para o controller de notícias. Se quiser apontar para o de usuários aponte em seu browser algum endereço semelhante a: http://localhost/zend_acl/usuarios. Classes com o prefixo "Application_" utilizam a nomenclatura padrão do Zend Framework e este namespace pode ser utilizado para diferenciar suas classes de aplicação das demais classes. Em casos mais simples eu prefiro não utilizar este prefixo e configuro no autoloader, demonstrado no artigo anterior, para utilizar um namespace vazio, isso vai mais de cada um e do tipo de aplicação. Se quiser retirar este prefixo sugiro que veja o artigo de Autenticação e coloque o método _initAutoload em seu Bootstrap. Att.
Responder	disse:	13 de setembro de 2010 às 21:05	Entendi, desculpe tantas perguntas, estou tentando compreender como funciona e é o primeiro artigo didático e atual que vejo, como ficaria o teste para redirecionar para os recurso permitidos, por exemplo, admin ir para página permitida a ele e escritor ir para a permitida a ele. Agora quanto ao namespace, mesmo no artigo de autenticação, o php acusou o erro por causa do prefixo "Aplication_", e eu coloquei exatamente como no modelo apresentado, obrigado.
Responder	Fernando Geraldo Mantoan disse:	13 de setembro de 2010 às 21:25	Bom, você pode verificar qual a role do usuário autenticado utilizando o método getRoleId(), e, no caso de ele ter a role "admin" modificar a rota que ele será direcionado, ficando algo assim:
Responder	disse:	13 de setembro de 2010 às 22:08	Valeu, tudo certo, obrigado.
Responder	disse:	17 de setembro de 2010 às 19:56	Gostaria de colocar este sistema de autenticação e autorização dentro de um módulo admin, onde o index verificaria se o usuário está logado ou não, não estando ele direcionaria para a verificação, caso ele estiver logado mostraria a index.phtml, mas não estou conseguindo configurar e fazer funcionar, estou meio perdido ainda com o zendframework, li vários tutoriais de como usar módulos mas não consegui nada, a estrutura de arquivos seria:
Responder	Fernando Geraldo Mantoan disse:	17 de setembro de 2010 às 20:19	Olá, a melhor maneira de te ajudar nisso é mantermos contato via e-mail. Por favor me mande um e-mail com seu Google Talk e podemos conversar melhor. Abraços.
Responder	disse:	17 de setembro de 2010 às 21:35	OK, enviei um email para 'contato@fernandomantoan.com', assim que puder me adicione.
Responder	Francisco Filho disse:	2 de fevereiro de 2011 às 12:43	Acho que só faltou uma coisa no tutorial.
Responder	Fernando Geraldo Mantoan disse:	25 de julho de 2012 às 14:34	Boa sugestão, se quiser contribuir com um exemplo disso no Github, pode fazer um pull request no repositório. Obrigado
Responder	william disse:	15 de fevereiro de 2011 às 12:51	otimu!!
Responder	Fernando Geraldo Mantoan disse:	25 de julho de 2012 às 14:37	Nesse caso não tem muito o que fazer William, acredito que seria melhor ver alguns artigos básicos de Zend Framework, para partir para esse. Fica a dica para o pessoal.
Responder	Gustavo Eidt disse:	19 de fevereiro de 2011 às 8:08	Concordo com o Fancisco, esse tutorial só serve para desenvolvimento de um sistema em que seria necessário o login para acessoa qualquer parte.
Responder	Gustavo Eidt disse:	19 de fevereiro de 2011 às 8:12	Melhorei um pouco a primeira modificação:
Responder	Caca disse:	4 de abril de 2011 às 13:53	Olá, implementei o tutorial e funciono perfeitamente mais como tive que expandir a aplicação usando modulos o acl nao funciona mais. No caso o Application_Plugin_Auth nao é instanciado e qndo eu uso ele pra iniciar no _init do bootstrap nao funciona tb ;/
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:08	Poderia dar mais detalhes dos erros? Att.
Responder	Marcius Oliveira disse:	7 de junho de 2011 às 11:31	Muito bom o artigo, meus parabéns
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:07	Muito obrigado Marcius.
Responder	Rafael Albani disse:	17 de junho de 2011 às 12:52	Olá, estou com um pequeno problema, quando início o sistema ele entra em um loop chamando sempre o método preDispatch() na classe Aplicacao_Plugin_Auth, agradeço desde já pela ajuda.
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:07	Estranho, verifique o código-fonte disponibilizado no repositório do GitHub, logo abaixo. Att.
Responder	Igor disse:	16 de julho de 2011 às 22:27	poderia ter deixado o codigo pra download
Responder	Fernando Geraldo Mantoan disse:	14 de fevereiro de 2012 às 13:56	Vou providenciar isso.
Responder	Fernando Geraldo Mantoan disse:	14 de fevereiro de 2012 às 14:37	Você pode fazer o download do código-fonte aqui: https://github.com/fernandouhu/zf-authorization-tutorial
Responder	Fernando Geraldo Mantoan disse:	29 de maio de 2012 às 8:34	https://github.com/fernandomantoan/zf-authorization-tutorial
Responder	Igor Carvalho de Paula disse:	17 de julho de 2011 às 18:36	e no caso de haver paginas publicas, sem restricao de acesso, como fazer?
Responder	Fernando Geraldo Mantoan disse:	14 de fevereiro de 2012 às 13:57	Você poderia implementar um mecanismo de whitelist, poderia ser algo como um array com as páginas públicas, e caso seja uma dessas páginas você não faz as verificações.
Responder	Danillo disse:	21 de outubro de 2011 às 14:07	Configurei tudo como deveria estar e está apresentando o erro
Responder	Danillo disse:	21 de outubro de 2011 às 15:18	Quando eu retiro a linha do Bootstrap a linha 17 "$aclSetup = new Aplicacao_Acl_Setup();"
Quando autentico como escritor aparece escritor Quando autentico como Admin aparece escritor…
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:06	Olá, tudo bem? Consulte o código fonte que disponibilizei no GitHub, verifique se com aquela base de código tudo funciona corretamente… Att.
Responder	Kayro disse:	23 de novembro de 2011 às 21:08	Legal! Bem didático!
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:07	Obrigado Kayro.
Responder	Programador disse:	2 de fevereiro de 2012 às 10:29	Artigo retirado daqui: http://devzone.zend.com/1258/zend_acl-and-mvc-integration-part-i-basic-use/
Responder	Fernando Geraldo Mantoan disse:	14 de fevereiro de 2012 às 13:52	Não, referência da documentação do Zend Framework, conforme citado nas referências externas, sendo essa a mesma fonte do artigo da DevZone.
Responder	Luiz Fernando - Agência Ampol disse:	14 de fevereiro de 2012 às 16:39	Fala fernando tranquilo? Conversei com voce a um tempo sobre autorização e você me respondeu no e-mail um tipo de "whitelist" … deu certinho e tal.. mas se eu tenho um controller "x" no modulo admin e um controller "x" no modulo default e liberar "x" no whitelist ele libera o acesso nos 2 módulos :P… então eu segui o exemplo do Gustavo Eidt e funcionou certinho em partes… ele não bloqueia mais as páginas para usuários não logados, porém os privilégios para admin e para writer não se diferenciam mais.. ou seja os 2 tem total acesso… Abraços
Responder	Fernando Geraldo Mantoan disse:	17 de fevereiro de 2012 às 21:16	Olá Luiz, tudo bem? Mas daí como ficou o código que está permitindo total acesso aos dois? Teria que analisar sucintamente cada pedaço de seu código, se quiser ajuda pode me contactar pelo e-mai. Abraços.
Responder	Josiel Rocha disse:	23 de fevereiro de 2012 às 13:50	Eu também tive o mesmo problema, mas fiz algumas adaptações e agora está tudo funcionando perfeitamente.
Responder	hugo machado disse:	22 de maio de 2012 às 23:04	Muito bom o artigo, dismitificou muita coisa em relação a Acl e Auth