Boas, vou mostrar hoje como habilitar e configurar o ACL (Access Control List) do CakePHP rodando sobre a engine PHP. Por padrão encontramos vastos exemplos com a engine Database (DbAcl) e toda a documentação que possuímos para o PhpAcl está contida no arquivo app/Config/acl.php. Mãos na massa! [UPDATE] Este post foi escrito em 2014 utilizando como base o CakePHP na ver
CREATE TABLE `roles` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `created` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE `users` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `role_id` int(10) unsigned NOT NULL, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL, `created` datetime DEFAULT NULL, `modified` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
$ ./app/Console/cake bake all Role $ ./app/Console/cake bake all UserPerfeito, já temos toda a estrutura básica que precisamos, resta apenas criar as actions de login e logout e a view para o login.
<?php // UsersControllers.php public function login() { if ($this->request->is('post')) { if ($this->Auth->login()) { $this->Session->setFlash('Logado com sucesso!'); $this->redirect($this->Auth->redirectUrl()); } $this->Session->setFlash('Dados de login inválidos'); } } public function logout() { $this->Auth->logout(); $this->redirect($this->Auth->redirectUrl()); } ?> //View/Users/login.ctp <?php echo $this->Form->create('User', array('id' => 'login')); ?> <p> <?php echo $this->Form->input('email'); ?> </p> <p> <?php echo $this->Form->input('password'); ?> </p> <p> <?php echo $this->Form->end(__('Realizar login')); ?> </p>Agora já temos o CRUD para Role, o CRUD para User, o login e o logout. Vamos inicialmente adicionar um papel (role) no sistema. Em seu browser acesse seu projeto e ao final da URL adicione /roles, caso já tenha uma barra no final, adicione roles apenas. Deve aparecer uma tela semelhante à abaixo. Clique em New Role e pra iniciar defina o nome como Admin, clique em "Submit". Em seguida cadastre um novo papel chamado Editor, apenas para exemplificar. Após isto o resultado devera ser como o apresentado abaixo. Agora cadastraremos um usuário para cada papel, um para o admin e outro para o editor. Perceba que no campo senha é perceptível que estou utilizando o algoritmo Blowfish (início da string com $2a$10$), isto é opcional, caso você faça com outro algoritmo qualquer ou mesmo deixando com o default do Cake já funciona.
// AppController.php public function beforeFilter() { // Definindo o algorítmo de hash para a senha (OPCIONAL) $this->Auth->authenticate = array('Blowfish' => array( 'userModel' => 'User', 'fields' => array('username' => 'email') )); // Informando controller/action para login $this->Auth->loginAction = array( 'controller' => 'users', 'action' => 'login' ); // controller/action após realizar o login $this->Auth->loginRedirect = array( 'controller' => 'pages', 'action' => 'home'); // controller/action após realizar o logout $this->Auth->logoutRedirect = array( 'controller' => 'users', 'action' => 'login' ); // Actions habilitadas para usuários não logados $this->Auth->allow('login', 'display', 'home'); // Definindo uma mensagem de erro do ACL $this->Auth->authError = 'Suas permissões não concedem acesso ao recurso solicitado.'; parent::beforeFilter(); }Vamos deixar o AppController completo para o funcionamento para somente então começarmos a definir nosso ACL. Ainda dentro do método beforeFilter adicione o seguinte trecho de código:
if ($this->Auth->user()) { if( !$this->isAuthorized() ) { $this->Session->setFlash($this->Auth->authError); $this->redirect($this->Auth->redirectUrl()); } $this->Auth->allow(); }Perceba que estamos chamando um método chamado isAuthorized, logo precisamos criá-lo:
protected function isAuthorized() { // verifica o recurso solicitado $aco = 'controllers/'.$this->params['controller']; //Informando qual é meu grupo $aro = $this->Auth->user('role_id'); //Retornando a validação do privilégio solicitante - recurso/privilegio return $this->Acl->check($aro, $aco, $this->params['action']); }No AppController tudo pronto! Agora temos mais dois passos, a definição do mecanismo do ACL a ser utilzado e sua configuração e as definições de nossas regras (listas).
/** * The class name and database used in CakePHP's * access control lists. */ Configure::write('Acl.classname', 'PhpAcl'); /**Ok, agora já temos a definição de que o ACL será tratado pelo mecanismo (engine) PhpAcl e não mais pelo DbAcl.
$config['map'] = array( 'Role' => 'User/role_id', );Em $config['alias'] apelidamos nossos papeis para que fique mais fácil o mapeamento. Como cadastramos os papéis admin e editor, adicionamos os mesmos nesta configuração informando qual é a model, o id e definimos seu apelido:
$config['alias'] = array( 'Role/1' => 'Role/admin', 'Role/2' => 'Role/editor', );A próxima configuração simplesmente deixamos como no exemplo abaixo:
$config['roles'] = array( 'Role/admin' => null, 'Role/editor' => null, );Neste ponto, caso um papel precise estender privilégios de outro(s) basta que adicionemos 'Role/y' => 'Role/x, Role/a ...' ao invés de 'Role/y' => null. A última configuração são as definições dos recursos/privilégios. Neste ponto é bom que fiquem claro alguns pontos:
$config['rules'] = array( 'allow' => array( '*' => 'Role/admin, Role/editor', ), 'deny' => array( //'controllers/roles/view' => 'Role/admin' ), );Como mencionei há pouco, se eu tivesse feito declarado '*' => 'Role/admin' numa linha e '*' => 'Role/editor' na outra com certeza teríamos problemas ao acessar qualquer recurso estando logado com o perfil editor. Por isso esta configuração deve estar toda na primeira linha, a não ser que você tenha uma regra muito específica, coloque tudo na primeira linha.
$config['rules'] = array( 'allow' => array( '*' => 'Role/admin, Role/editor', ), 'deny' => array( 'controllers/roles/add' => 'Role/admin' ), );Dê um refresh em seu browser e "ta dá"! Pode remover este boqueio, afinal de contas você está logado como admin e, neste caso o admin pode tudo. Deslogue-se do sistema através da URL /users/logout e logue-se como editor. Eu cadastrei um usuário com email: andrecardosodev@gmail.com e senha: andre. Novamente solicitei o recurso /users, e tendo logado corretamente vou para a lista de usuários. Como eu sou um editor de um blog por exemplo, não devo ter permissão para adicionar, editar e deletar um grupo e também não pode adicionar e nem deletar um usuário. Vamos às definições:
$config['rules'] = array( 'allow' => array( '*' => 'Role/admin, Role/editor', ), 'deny' => array( 'controllers/roles/(add|edit|delete)' => 'Role/editor', 'controllers/users/(add|edit|delete)' => 'Role/editor', ), );Pronto, tudo que especificamos será negado ao usuário logado com o papel editor, vamos ao teste? Acesse a URL /roles, ok, aqui você pode chegar, agora clique no botão "View" em um role qualquer. Aqui também, tudo ok. Agora na tela de visualização clique em "Edit", ops... você não possui acesso à este recurso, funcionou! Se quiser repetir os passos para os recursos de /users sinta-se à vontade. Devem ter as mesmas restrições que /roles, você não poderá adicionar, nem editar nem remover um usuário. Agora basta que as regras se apliquem à todos os papeis, recursos/privilégios de seu projeto. Por hoje é isso pessoal, espero que tenham gostado da explicação. Em um novo post dentro de alguns dias mostrarei como utilizar de fato o ACL, setando permissões especificas por usuários e não somente por grupos como mostrado aqui. Os fontes do exemplo aqui apresentado estão no Github. Aprenda mais sobre o CakePHP, clique aqui.