CakePHP 2.0 Authentication
Con CakePHP 2.0 ci sono tante novità. In questo post spiegherò come realizzare una semplice sistema di autenticazione per l'admin area, in cui abbiamo differenti users che possono accedervi, ma solo uno e' l'admin, gli altri sono amministratori con funzioni limitate. Per un piccolo sistema, con pochi utenti, ho deciso di non usare ACL, troppo ingombrante e dispendiosa, ma di scrivere un metodo apposito, allowedGroups da richiamare nelle azioni in cui voglio verificare che solo un determinato gruppo di utenti possa accedere a determinate funzioni. Alcune note sulle novità che influiscono sull'autenticazione.
- Sono supporati diversi tipi di autenticazione, configurabili tramite degli handlers, quello usato in questo articolo è il FormAuthenticate handler di default.
- Nelle versioni precedenti di CakePHP 2.0 bastava aggiungere l'Auth Component e chiamare la funzione login nello user controller, nella nuova versione, nella nostra function login, dovremo chiamare manualmente "$this->Auth->login()"
- La password non viene più crittata di default, il metodo va chiamato manualmente
Creiamo un database per gli users e uno per i groups
CREATE TABLE IF NOT EXISTS `groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `nome` varchar(70) NOT NULL, `description` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; CREATE TABLE IF NOT EXISTS `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `group_id` int(11) NOT NULL, `name` varchar(70) NOT NULL, `email` varchar(70) NOT NULL, `password` varchar(60) NOT NULL, `description` text NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
Creiamo i relativi controllers, models e views usando "cake bake".
Andiamo ad eliminare tutte le action e tutte le view che non saranno accessibili al di fuori dell'admin area. Rimuoviamo quindi,per esempio, dallo UserController le action delete, add, edit. Aggiungiamo i metodi per il login ed il logout dello user in app/Controllers/UsersController.php
/**
* Users Controller
*
* @property User $User
*/
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('admin_login');
}
/**
* login method
*
* @return void
*/
public function admin_login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$user_id = $this->Auth->user('id');
$group_id = $this->Auth->user('group_id');
$group = $this->User->getGroup($group_id);
$this->Session->write('Auth.User.group', $group);
$this->redirect(array('action' => 'profile', $user_id,
'admin' => true));
} else {
$this->Session->setFlash(__('email o password errata'),
'default', array(), 'auth');
}
}
}
/**
* logout method
*
* @return void
*/
public function admin_logout() {
$this->Session->setFlash('Sei ora sloggato dal sistema');
$this->Session->destroy();
$this->redirect($this->Auth->logout());
}
Come vedete ho utilizzato il metodo getGroup, che dovro' scrivere nel mio App/Model/User.php
function getGroup($group_id){
$conditions = array('id' => $group_id);
$group = $this->Group->field('nome', $conditions);
if ($group) {
return $group;
}
else {
return false;
}
}
Passiamo ora all'AppController.php, richiediamo l'autenticazione per chiunque voglia accedere all'admin area, e creiamo in App/Views/Layouts il file admin.ctp che conterrà il layout specifico per l'admin. Inoltre, andiamo a scrivere nella sessione il nome del gruppo, in modo da poterlo sempre leggere nella variabile $current_user, e da poterlo utilizzare sia per decidere quali elementi nelle view mostrare, sia per verificare che il nome del gruppo sia nell'elenco delle funzioni che vogliamo restringere solo ad alcuni gruppi.
class AppController extends Controller {
var $components = array('Auth','Session');
var $helpers = array('Session','Form','Html');
var $current_user = false;
function beforeFilter() {
if (isset($this->request->params['admin'])) {
$this->layout = 'admin';
$this->Auth->logoutRedirect = '/';
$this->Auth->authenticate = array(
AuthComponent::ALL => array(
'fields' => array(
'username' => 'email',
'password' => 'password'),
'userModel' => 'Users.User'
), 'Form'
);
} else {
$this->Auth->allow();
}
$this->current_user = $this->Auth->user();
}
function beforeRender() {
$this->set('current_user',$this->current_user );
}
function allowGroups($groups = array(), $options = array()){
if (empty($options['message'])) {
$options['message'] = 'non sei autorizzato ad accedere';
}
$group = $this->Session->read('Auth.User.group');
if (in_array($group, $groups) || ($groups[0] == "*")) {
return true;
}
else {
$this->Session->setFlash(__($options['message']));
$this->Session->destroy();
$this->redirect($this->Auth->logout());
}
}
}
Creaimo il file Views/Users/admin_login.ctp
<?
echo $this->Session->flash('auth');
echo $this->Form->create('User', array('url' => array('controller' => 'users', 'action' =>'login')));
echo $this->Form->input('User.email', array('label'=>'Email'));
echo $this->Form->input('User.password', array('label'=>'password'));
echo $this->Form->end('Loggati');
?>
Qui sotto un esempio su come utilizzare allowGroups.
#se voglio autorizzare tutti i gruppi esistenti
$this->allowGroups(array('*'));
#se voglio autorizzare solo il gruppo admin
$this->allowGroups(array('admin'));
#se voglio autorizzare admin e supervisori
$this->allowGroups(array('admin','supervisori'));
October 10th, 2011 - 18:15
Come devo configurare routes.php in questo caso?
October 11th, 2011 - 09:46
Ciao mlk,
la configurazione di routes.php resta invariata rispetto alla configurazione “standard ” della sezione admin.
Quindi:
Router::connect('/admin', array('controller' => 'users', 'action' => 'login', 'admin' => true));October 31st, 2011 - 01:21
Ciao, sto diventando matto.. ho seguito passo passo quello che hai indicato, ma non funziona. Quando vado a confermare il login mi dice sempre che utente e
password non sono validi.. Cosa mi posso essere perso?
November 5th, 2011 - 11:02
Ciao Ivan,
come prima cosa ti consiglierei di stampare a schermo la sql che ricerca le credenziali nella tabella user, controlla che l’hash della password contenuto nella sql coincida con quello nel tuo database.