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.
Feito o login como admin criado anteriormente (no meu caso foi email: admin@admin.com.br e senha: admin) você será redirecionado para o recurso que tentou acessar, no meu caso /users.
Clique no botão "New Role". Neste momento o acesso deve ser concedido com sucesso.
Agora no arquivo app/Config/acl.php bloqueie o acesso à adicionar novo papel do admin, somente para teste:
$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.