13.8 – Autenticação e Autorização Simples
O sucesso não consiste em não errar, mas em não cometer os mesmos equívocos mais de uma vez. (George Bernard Shaw)
Criar um aplicativo tipo blog com CakePHP 3 e autenticação simples
Tomando como ponto de partida o exemplo de aplicativo blog do site oficial do CakePHP:
https://book.cakephp.org/3.0/pt/tutorials-and-examples/blog/blog.html
Basicamente esta parte:
https://book.cakephp.org/3.0/pt/tutorials-and-examples/blog-auth-example/auth.html
Banco
-- Primeiro, criamos a tabela articles
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
-- Então inserimos articles para testes
INSERT INTO articles (title,body,created)
VALUES ('The title', 'This is the article body.', NOW());
INSERT INTO articles (title,body,created)
VALUES ('A title once again', 'And the article body follows.', NOW());
INSERT INTO articles (title,body,created)
VALUES ('Title strikes back', 'This is really exciting! Not.', NOW());
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(255),
role VARCHAR(20),
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
Criar aplicativo
cd varwww/html
cacomposer.phar create-project --prefer-dist cakephp/app blog
Configurar o banco em config/app.php
Configurar as rotas em config/routes.php para Users/login
Gerar o código
bin/cake bake all articles
bin/cake bake all users
Adicionar ao src/Controller/UsersController.php
use Cake\Event\Event;
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('add');
}
Alterar o src/Template/Users/login.ctp, apenas a linha do username para que receba o foco automaticamente ao ser aberta:
<?= $this->Form->input('username', ['autofocus' => true]) ?>
Adicione ao src/Controller/AppController.php, logo ao final do initialize():
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Articles',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
Ao final da classe:
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}
Adicione ao início do src/Controller/UsersController.php
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
// Permitir aos usuários se registrarem e efetuar logout.
// Você não deve adicionar a ação de "login" a lista de permissões.
// Isto pode causar problemas com o funcionamento normal do AuthComponent.
$this->Auth->allow(['add', 'logout']);
}
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Usuário ou senha ínvalido, tente novamente'));
}
}
public function logout()
{
return $this->redirect($this->Auth->logout());
}
Adicionar o suporte ao bcrypt para o hash das senhas
Editar src/Model/Entity/User.php e adicionar:
use Cake\Auth\DefaultPasswordHasher;
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
Criar o src/Template/Users/login.ctp contendo:
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Por favor informe seu usuário e senha') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
Execute no mysql
ALTER TABLE articles ADD COLUMN user_id INT(11);
Edite o AppController.php e mude o Auth para:
$this->loadComponent('Auth', [
'authorize' => ['Controller'], // Adicione está linha
'loginRedirect' => [
'controller' => 'Articles',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
Logo ao final:
public function isAuthorized($user)
{
// Admin pode acessar todas as actions
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// Bloqueia acesso por padrão
return false;
}
Adicione ao início do src/Controller/ArticlesController.php
public function isAuthorized($user)
{
// Todos os usuários registrados podem adicionar artigos
if ($this->request->getParam('action') === 'add') {
return true;
}
// Apenas o proprietário do artigo pode editar e excluí
if (in_array($this->request->getParam('action'), ['edit', 'delete'])) {
$articleId = (int)$this->request->getParam('pass.0');
if ($this->Articles->isOwnedBy($articleId, $user['id'])) {
return true;
}
}
return parent::isAuthorized($user);
}
Adicione ao src/Model/Table/ArticlesTable.php
public function isOwnedBy($articleId, $userId)
{
return $this->exists(['id' => $articleId, 'user_id' => $userId]);
}
Acesse
http://localhost/auth_blog/users/add
Adicione um usuário
Faça login com ele
http://localhost/auth_blog
Faça logout
http://localhost/auth_blog/users/logout
Veja que ele volta para a home do controller Pages.
Vamos mudar isso para que volte para o Users/login
Altere estas linhas no AppController:
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
'home'
]
Caso já tenhamos cadastrado todos os usuários do aplicativo devemos remover o add de:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow(['logout']);
}
Pronto. Nosso aplicativo agora somente será acessado por quem autorizarmos.
Bom exemplo:
https://lornajane.net/posts/2016/simple-access-control-cakephp3
Comments fornecido por CComment