Utilizando Zend_ACL -
Conforme falamos no post anterior sobre as Diferenças entre Zend_Auth e Zend_ACL, hoje falaremos, de uma forma mais prática, sobre a Zend_ACL (Access Control List).
O objetivo da Zend_ACL é verificar se o usuário tem permissão X para a área Y da aplicação.
Para isso é utilizada a seguinte nomenclatura:
- Role – Praticamente é o grupo ou o nível de hierarquia que o usuário foi designado (Ex: Administrator).
- Resource – Mais especificamente falando, é a área/recurso da aplicação ou seja: Ex: Treinamentos, Profile, Artigos, etc.
- Permission – Permissão de executar algum processo em um determinado resource. (Ex: Treinamentos (resource) – Adicionar (Permission)
Entendendo esses principios básicos tudo fica mais simples.
Abaixo segue uma classe que foi desenvolvida por um dos membros da devZone da Zend que faz todo o controle e mapeamento das permissions e resources dos usuários. Utilize a seguinte modelagem para o seu banco de dados para tal classe funcionar:
[sourcecode language='sql']
CREATE TABLE `acl_permissions` (
`role_id` int(11) NOT NULL,
`resource_id` int(11) NOT NULL,
`permission` varchar(64) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `acl_resources` (
`id` int(11) NOT NULL auto_increment,
`resource` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `resource` (`resource`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE `acl_roles` (
`role_id` int(11) NOT NULL auto_increment,
`role_name` varchar(64) NOT NULL,
PRIMARY KEY (`role_id`),
UNIQUE KEY `role_name` (`role_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE `acl_users` (
`id` int(11) NOT NULL auto_increment,
`role_id` int(11) NOT NULL,
`user_name` varchar(40) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_name` (`user_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
[/sourcecode]
Classe:
[sourcecode language='php']
class MyAcl extends Zend_Acl {
private $_db;
public $_getUserRoleName = null;
public $_getUserRoleId = null;
public $_user = null;
public function __construct($user)
{
$this->_user = $user ? $user : ‘Guest’;
$this->_db = Zend_Registry::get ( ‘database’ );
self::roleResource();
$getUserRole = $this->_db->fetchRow(
$this->_db->select()
->from(‘acl_roles’)
->from(‘acl_users’)
->where(‘acl_users.user_name = “‘ . $this->_user . ‘”‘)
->where(‘acl_users.role_id = acl_roles.role_id’));
$this->_getUserRoleId = $getUserRole['role_id'] ? $getUserRole['role_id'] : 4;
$this->_getUserRoleName = $getUserRole['role_name'] ? $getUserRole['role_name'] : ‘User’;
$this->addRole(new Zend_Acl_Role($this->_user), $this->_getUserRoleName);
}
private function initRoles()
{
$roles = $this->_db->fetchAll(
$this->_db->select()
->from(‘acl_roles’)
->order(array(‘role_id DESC’)));
$this->addRole(new Zend_Acl_Role($roles[0]['role_name']));
for ($i = 1; $i < count($roles); $i++) {
$this->addRole(new Zend_Acl_Role($roles[$i]['role_name']), $roles[$i-1]['role_name']);
}
}
private function initResources()
{
self::initRoles();
$resources = $this->_db->fetchAll(
$this->_db->select()
->from(‘acl_resources’));
foreach ($resources as $key=>$value){
if (!$this->has($value['resource'])) {
$this->add(new Zend_Acl_Resource($value['resource']));
}
}
}
private function roleResource()
{
self::initResources();
$acl = $this->_db->fetchAll(
$this->_db->select()
->from(‘acl_roles’)
->from(‘acl_resources’)
->from(‘acl_permissions’)
->where(‘acl_roles.role_id = acl_permissions.role_id’));
foreach ($acl as $key=>$value) {
$this->allow($value['role_name'], $value['resource'],$value['permission']);
}
}
public function listRoles()
{
return $this->_db->fetchAll(
$this->_db->select()
->from(‘acl_roles’));
}
public function getRoleId($roleName)
{
return $this->_db->fetchRow(
$this->_db->select()
->from(‘acl_roles’, ‘role_id’)
->where(‘acl_roles.role_name = “‘ . $roleName . ‘”‘));
}
public function insertAclUser()
{
$data = array(
‘role_id’ => $this->_getUserRoleId,
‘user_name’ => $this->_user);
return $this->_db->insert(‘acl_users’,$data);
}
public function listResources()
{
return $this->_db->fetchAll(
$this->_db->select()
->from(‘acl_resources’)
->from(‘acl_permissions’)
->where(‘resource_id = id’));
}
public function listResourcesByGroup($group)
{
$result = null;
$group = $this->_db->fetchAll($this->_db->select()
->from(‘acl_resources’)
->from(‘acl_permissions’)
->where(‘acl_resources.resource = “‘ . $group . ‘”‘)
->where(‘id = resource_id’)
);
foreach ($group as $key=>$value) {
if($this->isAllowed($this->_user, $value['resource'], $value['permission'])) {
$result[] = $value['permission'];
}
}
return $result;
}
public function isUserAllowed($resource, $permission)
{
return ($this->isAllowed($this->_user, $resource, $permission));
}
}
[/sourcecode]
Bacana o Blog. Parabéns pelas matérias sobre PHP.
Grande abraço
Thiago Toledo
Comentário by Thiago Toledo — 24/08/2008 @ 15:19
Muito legal a iniciativa mesmo, mas teria a possibilidade de me ajudar com a view ???
Comentário by Lord Shutdown — 25/09/2008 @ 12:57
Olá,
Qual view você diz?
Abraços
Comentário by Wesley — 25/09/2008 @ 15:32
Pow, a respeito da view eu resolvi, mas encontro-me com outro problema.
$select = $this->_db->select();
$select->from(‘acl_roles’);
$select->join(‘usuario’, ‘usuario.id_nivelacesso = acl_roles.id’ ,’username’);
$select->where(‘usuario.username = “‘ . $this->_user . ‘”‘);
$getUserRole = $this->_db->fetchAll($select);
ele me diz que eu nao posso pegar um objeto e converter para string, já tentei umas 197834692341 d coisas e nada deu certo. Aguardo uma ajuda, pq nem o google deu jeito.
Abraços
Comentário by Lord Shutdown — 30/09/2008 @ 8:57
Opa, só para entender o que está havendo. Você está usando a classe postada acima?
Ou você quer saber como transformar um fetchAll em um array por exemplo?
Abraços
Comentário by Wesley — 30/09/2008 @ 9:35
Usei a classe de cima como base, alterei algumas coisas .. sendo que, o que eu preciso e fazer um controle de acesso que todas as roles, resources e permissions estejam em tabelas junto com a Zend_Auth … e o select nao me deixa passar a auth como parametro pq ele diz que nao posso converte-la para string .. o q devo fazer ?
Comentário by Lord Shutdown — 30/09/2008 @ 10:11
Recomendo que você separe a autenticação da ACL.
Trabalhe com processos separados, ou seja, primeiro autentique e depois utilize o processo da ACl.
De qualquer forma o problema do String é simples. Quando vc da um fetchAll o resultado pelo jeito ainda está no objeto. Utilize um fetch que gere o resultado num array associativo exemplo:
$select = $db->select()
->from(‘users’);
$exec = $select->query();
$result = $exec->fetchAssoc();
Tente isso. Outra coisa, verifique se esse seu select está funcionando mesmo.
Abraços
Comentário by Wesley — 30/09/2008 @ 12:37
Eu agradeço a atenção, vou tentar aki e posto o resultado completo caso tenha sucesso ….
[]s
Comentário by Lord Shutdown — 30/09/2008 @ 15:04
Ser novato de Zend e ter d desenvolver pra cliente é sinistro.
Realmente estou com muita dificuldade para fazer funcionar esse exemplo, que é excelente, proposto. Teria a possibilidade de enviar esse exemplo completo em ZIP por e-mail para mim?
Agradeço novamente a atenção
P.S.: Acredito que meu e-mail apareça na validação do post em seu blog, mas caso contrario envio o e-mail via post e você não valida.
Comentário by Lord Shutdown — 01/10/2008 @ 9:42
Olá, vou verificar aqui e lhe envio por email assim que possível.
Tenho seu email aqui.
Você você já viu nosso treinamento de ZF?
Comentário by Wesley — 01/10/2008 @ 10:05
Pow, eu consegui aki, comprei ate o livro do flavio lisboa, e agora to fazendo um d menu exclusivo com base de dados. Depois qdo eu terminar aqui, envio pra vc pra passar pra outras pessoas .. com certeza sera de grande ajuda.
obg pela atenção
compartilhando conhecimentos sempre
[]s
Comentário by Lord Shutdown — 06/10/2008 @ 15:26
Fala ae pessoal, blz?
Parabéns pelo post, é excelente!
Bom, como sou iniciante, não sei como fazer um exemplo prático usando esta classe…já tenho um sistem de login integrado com extjs e queria implementar um menu dinamico, com níveis de permissão, administrador ver todos os menus, usuários ve x menus, etc…tudo gerenciado pelo admin (db), sem modificar o código…
Acredito que esta classe me ajude com isso…
Se algum de vocês tiver um exemplo prático, por favor me manda por email.
ps: email (internetwaves@gmail.com)
Obrigado,
Rodrigo
Comentário by Rodrigo — 07/10/2008 @ 11:44
Olá pessoal,
Gostei muito do plugin… Ando atrás de uma coisa parecida e principalmente que seja dinamica como esta, onde se pode remover e adicionar tudo pela base de dados sem escrever nada à “mão”…
Se me puderem enviar o sistema completo… Agradecia imenso, enviem para vieira@miguelvieira.com.pt
Obrigado..
Comentário by Miguel Vieira — 27/10/2008 @ 20:56
Olá, vi o exemplo acima mas fiquei meio confuso, estou fazendo o curso do Zend na School, está excelente, estou aprendendo muito, mas se puderem me enviar algo mais completo de ZEND_ACL para criar as permissões e até montar um menu dinâmico ficaria muito grato.Se alguém puder me ajudar.Obrigado (amfcom@gmail.com)
Comentário by André — 13/03/2009 @ 21:37
Gostaria também deste exemplo completo com ZEND_ACL, pois não consigo entender na prática como vou construir um menu dinâmico com base nas permissões.
(albertotr@gmail.com)
Comentário by Alberto — 19/03/2009 @ 14:48
Boa Tarde
Estou começando com o Zend Framework, e gostaria de saber o que seria especificamente e onde elas se enquadrão:
permissions
resources
roles
eu imagino que roles seja algo parecido com perfil, mas nao consegui identificar o que seria resources! permissions ta beleza são permissões! mas poderia me explicar como esses elementos se relacionam especificamente!?!?!?!
Desde já agradeço pela sua compreenção! e desculpe a pergunta meio banal, mas nunca mechi com ZF e quando fazia sistema de autenticação eu só tinha uma tabela de MENU_USUARIO
Comentário by Renato — 25/03/2009 @ 15:17
Também sou iniciante no ZF e ficaria muito grato se algum de vocês disponibilizasse um exemplo de controle ACL para Menu, com banco de dados.
Desde já agradeço a atenção de todos!
E-mail: mcmjunior@gmail.com
Comentário by Junior — 02/06/2009 @ 15:55