Академический Документы
Профессиональный Документы
Культура Документы
Conceitos
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.
Existem alguns termos utilizados para melhor explanar as entidades envolvidas no controle de acesso,
cada um deles é detalhado a seguir.
Papel (role)
Um papel corresponde a uma responsabilidade de um usuário dentro de um sistema como, por exemplo, o
papel de "colunista" ou de "membro". Isso é encapsulado através da classe Zend_Acl_Role, que é uma
classe simples que apenas armazena o nome do papel. Existe também herança de papéis, onde ao se
herdar de um papel, é possível fazer tudo que o papel pai faz, além das ações específicas do papel filho.
Para se criar um papel e adicioná-lo na lista de controle de acesso, o seguinte código é necessário:
$papelMembro = new Zend_Acl_Role('membro');
$acl = new Zend_Acl();
$acl->addRole($papelMembro);
Para utilizar a herança de papéis, basta passar o nome do papel pai como segundo parâmetro do
método addRole(). Para exemplificar isso, o papel "colunista" irá herdar de "membro", pois um colunista
pode fazer tudo o que um membro pode, além de possuir permissões especiais para criar colunas. O
código desse exemplo é apresentado abaixo:
$papelMembro = new Zend_Acl_Role('membro');
$papelColunista = new Zend_Acl_Role('colunista');
$acl = new Zend_Acl();
$acl->addRole($papelMembro);
$acl->addRole($papelColunista, 'membro');
Recurso (resource)
Um recurso é algo a ser protegido, o que pode ser um controlador ou uma ação. Um recurso é encapsulado
1 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
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.
Privilégio (privilege)
Um dado recurso pode ter diversas permissões a um determinado papel, essas permissões são, tipicamente,
baseadas nas operações que serão executadas. Exemplos dessas operações podem ser ações de um
controlador, como, por exemplo: "adicionar" e "visualizar". Esse tipo de acesso exigido é facilmente
configurado com dois métodos do Zend_Acl: allow() e deny(). Um exemplo permitindo e negando ações
do controladorartigos ao papel membro é exibido a seguir:
$acl->allow('membro', 'artigos', 'visualizar');
$acl->deny('membro', 'artigos', 'adicionar');
Após permitir ou negar privilégios, é possível verificar se um determinado papel tem acesso a um
privilégio com o seguinte código:
if ($acl->isAllowed('member', 'artigos', 'visualizar') {
echo "acesso permitido";
}
Esses são os principais conceitos e métodos relacionados aos componentes de autorização do Zend
Framework, agora é hora de implementar um sistema de autorização integrado com o MVC do
framework. Existem diversas formas de se implementar essa funcionalidade, a maneira demonstrada neste
artigo é apenas uma delas.
Codificando a Autorização
Após uma introdução sobre os componentes de autorização do Zend Framework, é hora de integrar as
funcionalidades para aplicar a autorização ao MVC do framework. Antes de mais nada, estou partindo do
pressuposto de que o leitor possui todos os fontes do artigo Autenticação com Zend Framework, para
reaproveitar o código desenvolvido neste artigo.
O banco de dados do artigo anterior sofreu algumas modificações, agora foi criada uma tabela para
armazenar os perfis (papéis) suportados por essa aplicação. Dois perfis de exemplo são criados, o primeiro
corresponde ao perfil de administrador, que pode ter acesso a todos os recursos protegidos, e o segundo ao
perfil de escritor, que pode apenas acessar o controlador de notícias. Um usuário para cada perfil também
foi criado. O SQL do banco de dados é apresentado abaixo:
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,
2 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
A próxima etapa é adicionar ao Bootstrap a inicialização da classe de ACL que irá popular todas as
regras de autorização suportadas pela aplicação. Dentro do arquivo application/Bootstrap.php basta
adicionar o seguinte método à classe Bootstrap:
protected function _initAcl()
{
$aclSetup = new Aplicacao_Acl_Setup();
}
No artigo anterior, foram criados os controladores: noticias e auth. Agora, basta criar o
controlador usuarios, que será acessível pelo papeladmin, adicionar novas ações a este novo controlador
e ao controlador noticias e, por último, adicionar uma nova ação ao controlador error.
zf create controller usuarios
zf create action adicionar noticias
zf create action adicionar usuarios
zf create action forbidden error
A ação forbidden ficará responsável por informar ao usuário que um determinado acesso não foi
autorizado pela aplicação. Para exibir essa mensagem ao usuário, basta adicionar o seguinte conteúdo ao
arquivo views/scripts/error/forbidden.phtml:
<div style="color: #f00;">Você não está autorizado a ver esta pági
Com isso, a parte inicial da aplicação está pronta, agora é hora de implementar a classe responsável por
popular o componente Zend_Acl.
Populando a ACL
A classe Bootstrap irá inicializar uma classe chamada Aplicacao_Acl_Setup, que ficará responsável por
popular todos os dados relacionados a papéis, recursos e privilégios do componente Zend_Acl. Essa
classe é apresentada abaixo e deve ser gravada no arquivo library/Aplicacao/Acl/Setup.php.
<?php
class Aplicacao_Acl_Setup
{
/**
* @var Zend_Acl
*/
protected $_acl;
3 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
$this->_initialize();
}
A primeira etapa dessa classe é configurar os papéis. Nesse caso, foram criados os
papéis guest, writer e admin. O papel guest foi criado como um facilitador, já que não será utilizado.
Pode ocorrer de a aplicação liberar determinados acessos a usuários não-logados, aí que entra esse papel.
O papel writer terá os mesmos acessos de guest, além de acessos específicos, assim como o
papel admin terá os mesmos acessos que guest e writer, além de outras permissões.
Após ter os papéis definidos, são adicionados os recursos protegidos. Nesse caso, os recursos são os
controladores auth, error, noticias eusuarios. A próxima etapa é definir os privilégios de um
determinado papel a um determinado recurso. O papel guest pode acessar ações de erro e a página de
login, já o papel writer pode acessar as ações de guest, as ações do controlador de notícias e a ação de
logout do controlador auth. Já o papel admin pode acessar o mesmo que os outros dois papéis, além das
ações do controlador de usuários.
Por último, essa ACL é adicionada ao Zend_Registry, para que em outras partes da aplicação ela esteja
acessível e devidamente populada.
Verificação de permissões
Tendo a ACL devidamente configurada, agora será possível verificar as permissões do usuário. Para isso,
foi criado um plugin que é adicionado ao Zend_Controller_Front no arquivo de configuração definido
na primeira etapa das implementações. Esse plugin terá como pai da classe
4 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
5 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
Primeiramente são definidas as rotas padrão para o caso do usuário não estar logado ou não estar
autorizado a ver uma determinada página. Essas rotas são,
consecutivamente: auth/login e error/forbidden. No construtor é recuperada a instância atual
de Zend_Auth e Zend_Acl, ambas usadas no processo de verificação do usuário logado.
A primeira etapa do método preDispatch() é verificar se o usuário está logado e, caso não esteja, os
parâmetros da requisição são configurados para a rota de login. A segunda etapa é o caso de o usuário
estar logado. Nessa etapa, o objeto que representa o usuário logado é recuperado e é feita uma verificação
se esse usuário possui o privilégio correspondente à ação do controlador requisitado. Caso não possua, ou
o recurso que representa o controlador não exista, ele é redirecionado para a rota de acesso proibido. Se
nenhuma dessas verificações negar o acesso ao usuário, significa que ele está apto a acessar a requisição
em questão, portanto os parâmetros dessa requisição são mantidos e o fluxo prossegue.
Models
Tendo todo o processo de verificação pronto, a próxima etapa é criar as classes com regras de negócio da
parte de autenticação. Já que, diferente do artigo anterior, este artigo envolve o MVC do Zend
Framework, toda a parte de regra de negócio é implementada na camada referente ao Model. A primeira
classe criada é a classe que representa um usuário da aplicação. Ela implementará a
interface Zend_Acl_Role_Interface, que permite que ela seja tratada como um papel do
componente Zend_Acl. Essa classe exige que o método getRoleId() seja implementado e retorne o
identificador correspondente ao papel em questão. Essa classe é bem simples e possui apenas
métodos getters e setters. Ela deverá estar no arquivo models/Usuario.php.
<?php
class Model_Usuario implements Zend_Acl_Role_Interface
{
private $_userName;
private $_roleId;
private $_fullName;
6 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
A próxima etapa é implementar a classe que cuidará da regra de negócio de login. Essa classe terá apenas
um método estático, responsável por fazer o login do usuário na aplicação. A principal diferença deste
método de login com o apresentado no artigo anterior é a modificação da consulta ao banco de dados,
para adicionar a tabela perfil aos dados retornados pelo Zend_Auth_Adapter_DbTable. O
método join() de Zend_Db_Select adicionará a tabela perfil com o alias "p", onde a coluna perfil_id da
tabela usuario seja igual a coluna id da tabela perfil, retornando a coluna "nome" da tabela "perfil" com
o alias "nome_perfil". Após validar o login, o objeto retornado pelo adapter é mapeado para um objeto do
tipo Model_Usuario e, por último, ele é armazenado à sessão do Zend Framework. Esse model ficará no
arquivo models/Auth.php e deve possuir o seguinte conteúdo:
<?php
class 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('nom
//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');
$storage = $auth->getStorage();
$storage->write($usuario);
return true;
}
throw new Exception('Nome de usuário ou senha inválida');
}
}
Agora que toda a regra de negócio foi delegada à camada Model, o controller de autenticação sofre
algumas modificações para utilizar essa classe. Nesse caso, ele chamará o método
estático Model_Auth::login(), e, caso este lance alguma exceção, irá armazenar a mensagem ao
helper FlashMessenger e exibi-la em cima do formulário de login. A classe modificada é apresentada
abaixo e, logo em seguida, a view correspondente a essa ação de login é apresentada. O formulário de
7 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
try {
Model_Auth::login($login, $senha);
//Redireciona para o Controller protegido
return $this->_helper->redirector->goToRoute( array('
} 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);
}
}
}
<h2>Login</h2>
<?php echo ( sizeof( $this->messages ) > 0 ) ? '<div style="color: #f00;">' . $this->messages
<?php echo $this->form; ?>
A última etapa é modificar as views dos controladores noticias e usuarios. Essas views são extremamente
simples e irão conter apenas uma mensagem de boas-vindas e um link para logout. O
arquivo views/scripts/noticias/index.phtml deve conter o seguinte conteúdo:
<h2>Bem-vindo Escritor</h2>
<a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'logout', 'module' =
Logout
</a>
8 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
<h2>Bem-vindo Admin</h2>
<a href="<?php echo $this->url(array('controller' => 'auth', 'action' => 'logout', 'module' =
Logout
</a>
Funcionamento
Após todas as etapas estarem concluídas, a aplicação está devidamente protegida, tanto na questão de
permitir apenas usuários logados, como em autorizar aos usuários apenas alguns privilégios baseados em
seu perfil. Para o meu caso, a URL da aplicação ficou apontada para:http://localhost/zend_acl, e
qualquer tentativa de acessar controllers internos são redirecionadas à pagina de login. Após o login, a
aplicação permite ou proíbe o acesso, de acordo com o perfil logado. Abaixo são apresentadas algumas
screenshots de cada parte funcional dessa aplicação:
Conclusão
9 de 10 16/9/2010 20:45
iMasters - Por uma Internet mais criativa e dinâmica http://imasters.uol.com.br/artigo/18025/zend/autorizacao_com_zend_fr...
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.
Referências
10 de 10 16/9/2010 20:45