Posts Tagged Controle de Acesso
Controle de acesso com Zend_Acl
Posted by Thiago Colares in PHP, Zend Framework on May 5, 2010
A muito tempo não posto um bom “php” por aqui, então vamos lá… A algum tempo postei sobre Zend_Auth e fiquei devendo um post sobre Zend_Acl.
Problemas com controle de acesso viram soluções com Zend_Acl. A alguns meses precisei implementar o controle de acesso para um sistema com ZF e me encantei com a facilidade e praticidade do Acl. Primeiro, alguns conceitos básicos…
Roles: São os perfis definidos. Basicamente, quem tem ou não acesso.
Resources: São as funcionalidades a serem controladas.
Usarei como exemplo o código que implementei já citado anteriormente. Criamos uma tabela simples para as funcionalidades, uma para perfis e duas tabelas associativas: uma entre perfis e funcionalidades e outra entre usuários e funcionalidades. Para abreviar, vou mostrar somente a tabela de funcionalidades:
-
cd_funcionalidade NUMBER NOT NULL,
-
descricao VARCHAR2(150) NOT NULL,
-
funcionalidade VARCHAR2(200) NOT NULL,
-
PRIMARY KEY(cd_funcionalidade));
Nesta tabela de funcionalidades será cadastrado uma descrição e a url da funcionalidade (resource). Ex: /usuarios ou /administracao/perfil
Assim que o usuário se autentica no sistema, redireciono ele para um controller chamado “acesso” para montar o objeto Acl. Neste exemplo, o usuário pode ter as funcionalidades definidas pelo perfil ou definidas diretamente para ele. Da seguinte forma…
-
-
//Model da tabela associativa entre Usuário e Perfil
-
$objPerfilUsuario = new PerfilUsuario();
-
-
//Model da tabela de funcionalidades
-
$objFuncionalidade = new Funcionalidade();
-
-
//Dados da autenticação do usuário…
-
$nsAutenticacao = new Zend_Session_Namespace('autenticacao');
-
-
$idUser = $nsAutenticacao->id;
-
-
//Recuperando os dados do perfil do usuário
-
$arrPerfil = $objPerfilUsuario->getPerfilUsuario($idUser);
-
-
$nsAutenticacao->idPerfil = $arrPerfil['idPerfil'];
-
$nsAutenticacao->perfil = $arrPerfil['perfil'];
-
-
//Criando o objeto Acl
-
$acl = new Zend_Acl();
-
-
//Crio uma role com o nome do perfil do usuário
-
$acl->addRole(new Zend_Acl_Role($arrPerfil['perfil']));
-
-
//Funcionalidades definidas por perfil
-
-
//Recupero as funcionalidades definidas para o perfil…
-
$arrFuncionalidades = $objFuncionalidade->getFuncionalidadesAcl($arrPerfil['idPerfil']);
-
-
//Em um foreach, adiciono ao objeto Acl as funcionalidades (resources) e a permissão
-
foreach($arrFuncionalidades['allow'] as $array) {
-
$acl->add(new Zend_Acl_Resource($array));
-
$acl->allow($arrPerfil['perfil'],$array);
-
}
-
-
if(isset($arrFuncionalidades['deny'])){
-
foreach($arrFuncionalidades['deny'] as $array) {
-
$acl->add(new Zend_Acl_Resource($array));
-
$acl->deny($arrPerfil['perfil'],$array);
-
}
-
}
-
-
//Funcionalidades definidas por usuário
-
-
//Model da tabela associativa entre usuário e funcionalidade…
-
$objUserFunc = new UsuarioFuncionalidade();
-
-
//Recupero as funcionalidades definidas para o usuário
-
$arrFuncUser = $objUserFunc->getFuncionalidadesAcl($idUser);
-
-
//Como a role já está criada no objeto Acl, apenas adiciono as permissões…
-
foreach($arrFuncUser as $arr) {
-
$acl->allow($arrPerfil['perfil'],$arr);
-
}
-
-
//Crio um namespace para o objeto Acl
-
$ns = new Zend_Session_Namespace();
-
$ns->acl = $acl;
Obs: Nos métodos getFuncionalidadesAcl() das modelos utilizadas retorno um array com a seguinte estrutura: array(’idDaFuncionalidade’ => ‘Url da funcionalidade’). No caso da model Funcionalidades, existe uma particularidade: o array “deny”:
-
-
public function getFuncionalidadesAcl($idPerfil) {
-
-
$select = 'Seu sql';
-
-
$rs = $this->fetchAll($select)->toArray();
-
$arrFinal = array();
-
-
foreach($rs as $arrAllow) {
-
-
$arrFinal['allow'][$arrAllow['cd_funcionalidade']] = $arrAllow['TX_URL'];
-
-
}
-
-
unset($rs);
-
-
$rs = $this->fetchAll()->toArray();
-
-
/** Neste foreach eu verifico se existe alguma funcionalidade que está cadastrada na tabela funcionalidades
-
* mas não está definida para o perfil. Se existir, precisamos tirar a permissão de acesso a ela.
-
* Toda funcionalidade que não estiver cadastrada na tabela de funcionalidades tem seu acesso liberado.
-
*/
-
-
-
foreach($rs as $arrDeny) {
-
if((!array_key_exists($arrDeny['cd_funcionalidade'], $arrFinal['allow'])) AND ($arrDeny['funcionalidade'])) {
-
$arrFinal['deny'][$arrDeny['cd_funcionalidade']] = $arrDeny['funcionalidade'];
-
}
-
}
-
-
return $arrFinal;
-
-
}
Pronto, o objeto Acl está criado e com as permissões setadas. Agora basta fazer a verificação sempre que o usuário tentar acessar os controllers do sistema. No caso deste exemplo, temos uma classe que extende da Zend_Controller_Action, ou seja, qualquer redirecionamento do sistema passará por ela. Nesta classe, adicionei o seguinte código para realizar a verificação da permissão:
-
-
//Recupero o objeto Acl do namespace…
-
$ns = new Zend_Session_Namespace();
-
-
if(isset($ns->acl)) {
-
$acl = $ns->acl;
-
//Monto a Url que está tentando ser acessada para a verificação…
-
$url = '/'.$this->_request->getControllerName().'/'.$this->_request-getActionName();
-
-
if($acl->has($url)) {
-
-
//Recupero os dados de autenticação do usuário…
-
$nsAutenticacao = new Zend_Session_Namespace('autenticacao');
-
-
//Verifico se o perfil do usuário tem acesso à url
-
if(!$acl->isAllowed($nsAutenticacao->perfil, $url)) {
-
-
//Caso não seja, redireciono o usuário para algum lugar avisando que ele não tem acesso…
-
$this->_redirect('/index/sem-acesso');
-
}
-
}
-
}
Caso o usuário tenha o acesso, não preciso fazer nada… Apenas deixo a requisição continuar a sua execução e o usuário chegará à url.
Simples, não? Caso tenha alguma dúvida ou tenha alguma crítica ou sugestão para melhorar, deixe seu comentário ou entre em contato por email
Um abraço!



