CakePHP 1.3 - Simple ACL Example ================================ Public domain ******************************************************************************** ### SQL CREATE DATABASE blog; USE blog; CREATE TABLE users ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(255) NOT NULL UNIQUE, password CHAR(40) NOT NULL, group_id INT(11) NOT NULL, created DATETIME, modified DATETIME ); CREATE TABLE groups ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, created DATETIME, modified DATETIME ); CREATE TABLE posts ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, user_id INT(11) NOT NULL, title VARCHAR(255) NOT NULL, body TEXT, created DATETIME, modified DATETIME ); CREATE TABLE widgets ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, part_no VARCHAR(12), quantity INT(11) ); ******************************************************************************** ### Commands cp -a cakephp-cakephp-8236c7e/ weblog cd weblog chown -R apache app/tmp/ ******************************************************************************** ### Create app/config/database.php 'mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'root', 'password' => '', 'database' => 'blog', 'prefix' => '', //'encoding' => 'utf8', ); } ******************************************************************************** ### Check http://localhost/weblog/ ******************************************************************************** ### Bake cake/console/cake bake all group cake/console/cake bake all post cake/console/cake bake all user cake/console/cake bake all widget chown -R apache app/tmp/ ******************************************************************************** ### Add to app/controllers/users_controller.php function login() { if ($this->Session->read('Auth.User')) { $this->Session->setFlash('You are logged in!'); $this->redirect('/', null, false); } } function logout() { $this->Session->setFlash('Good-Bye'); $this->redirect($this->Auth->logout()); } ******************************************************************************** ### Create app/views/users/login.ctp

Login

Session->flash('auth'); echo $this->Form->create('User', array('url' => array('controller' => 'users', 'action' =>'login'))); echo $this->Form->inputs(array('legend' => __('Login', true),'username','password')); echo $this->Form->end('Login'); ?> ******************************************************************************** ### Prepare customized default layout cp cake/libs/view/layouts/default.ctp app/views/layouts/ ******************************************************************************** ### In app/views/layouts/default.ctp , add to body Session->flash('auth'); ?> ******************************************************************************** ### Create app/app_controller.php Auth->authorize = 'actions'; $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login'); $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'logout'); $this->Auth->loginRedirect = array('controller' => 'posts', 'action' => 'add'); } } ?> ******************************************************************************** ### Temp add to app/controllers/users_controller.php ### Temp add to app/controllers/groups_controller.php function beforeFilter() { parent::beforeFilter(); $this->Auth->allow(array('*')); } ******************************************************************************** ### Initialize the Db Acl tables cake/console/cake schema create DbAcl chown -R apache app/tmp/ ******************************************************************************** ### Acts As a Requester 0. Add to app/models/user.php var $actsAs = array('Acl' => 'requester'); function parentNode() { if (!$this->id && empty($this->data)) { return null; } $data = $this->data; if (empty($this->data)) { $data = $this->read(); } if (empty($data['User']['group_id'])) { return null; } else { return array('Group' => array('id' => $data['User']['group_id'])); } } 0. Add to app/models/group.php var $actsAs = array('Acl' => array('type' => 'requester')); function parentNode() { return null; } ******************************************************************************** ### Add new groups: administrators, managers, users http://localhost/weblog/groups/add ******************************************************************************** ### Add new users in each group: admin, operator, test http://localhost/weblog/users/add ******************************************************************************** ### Add to app/models/user.php /** * After save callback * * Update the aro for the user. * * @access public * @return void */ function afterSave($created) { if (!$created) { $parent = $this->parentNode(); $parent = $this->node($parent); $node = $this->node(); $aro = $node[0]; $aro['Aro']['parent_id'] = $parent[0]['Aro']['id']; $this->Aro->save($aro); } } ******************************************************************************** ### Creating ACOs (Access-Control-Objects) cake/console/cake acl create aco root controllers cake/console/cake acl create aco controllers Posts cake/console/cake acl create aco Posts add cake/console/cake acl create aco Posts edit cake/console/cake acl create aco controllers Widgets cake/console/cake acl create aco Widgets add cake/console/cake acl create aco Widgets edit chown -R apache app/tmp/ ******************************************************************************** ### In app/app_controller.php add the following to the beforeFilter: $this->Auth->actionPath = 'controllers/'; ******************************************************************************** ### An Automated tool for creating ACOs, add to app/app_controller.php function build_acl() { if (!Configure::read('debug')) { return $this->_stop(); } $log = array(); $aco =& $this->Acl->Aco; $root = $aco->node('controllers'); if (!$root) { $aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers')); $root = $aco->save(); $root['Aco']['id'] = $aco->id; $log[] = 'Created Aco node for controllers'; } else { $root = $root[0]; } App::import('Core', 'File'); $Controllers = App::objects('controller'); $appIndex = array_search('App', $Controllers); if ($appIndex !== false ) { unset($Controllers[$appIndex]); } $baseMethods = get_class_methods('Controller'); $baseMethods[] = 'build_acl'; $Plugins = $this->_getPluginControllerNames(); $Controllers = array_merge($Controllers, $Plugins); // look at each controller in app/controllers foreach ($Controllers as $ctrlName) { $methods = $this->_getClassMethods($this->_getPluginControllerPath($ctrlName)); // Do all Plugins First if ($this->_isPlugin($ctrlName)){ $pluginNode = $aco->node('controllers/'.$this->_getPluginName($ctrlName)); if (!$pluginNode) { $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginName($ctrlName))); $pluginNode = $aco->save(); $pluginNode['Aco']['id'] = $aco->id; $log[] = 'Created Aco node for ' . $this->_getPluginName($ctrlName) . ' Plugin'; } } // find / make controller node $controllerNode = $aco->node('controllers/'.$ctrlName); if (!$controllerNode) { if ($this->_isPlugin($ctrlName)){ $pluginNode = $aco->node('controllers/' . $this->_getPluginName($ctrlName)); $aco->create(array('parent_id' => $pluginNode['0']['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginControllerName($ctrlName))); $controllerNode = $aco->save(); $controllerNode['Aco']['id'] = $aco->id; $log[] = 'Created Aco node for ' . $this->_getPluginControllerName($ctrlName) . ' ' . $this->_getPluginName($ctrlName) . ' Plugin Controller'; } else { $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName)); $controllerNode = $aco->save(); $controllerNode['Aco']['id'] = $aco->id; $log[] = 'Created Aco node for ' . $ctrlName; } } else { $controllerNode = $controllerNode[0]; } //clean the methods. to remove those in Controller and private actions. foreach ($methods as $k => $method) { if (strpos($method, '_', 0) === 0) { unset($methods[$k]); continue; } if (in_array($method, $baseMethods)) { unset($methods[$k]); continue; } $methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method); if (!$methodNode) { $aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method)); $methodNode = $aco->save(); $log[] = 'Created Aco node for '. $method; } } } if(count($log)>0) { debug($log); } } function _getClassMethods($ctrlName = null) { App::import('Controller', $ctrlName); if (strlen(strstr($ctrlName, '.')) > 0) { // plugin's controller $num = strpos($ctrlName, '.'); $ctrlName = substr($ctrlName, $num+1); } $ctrlclass = $ctrlName . 'Controller'; $methods = get_class_methods($ctrlclass); // Add scaffold defaults if scaffolds are being used $properties = get_class_vars($ctrlclass); if (array_key_exists('scaffold',$properties)) { if($properties['scaffold'] == 'admin') { $methods = array_merge($methods, array('admin_add', 'admin_edit', 'admin_index', 'admin_view', 'admin_delete')); } else { $methods = array_merge($methods, array('add', 'edit', 'index', 'view', 'delete')); } } return $methods; } function _isPlugin($ctrlName = null) { $arr = String::tokenize($ctrlName, '/'); if (count($arr) > 1) { return true; } else { return false; } } function _getPluginControllerPath($ctrlName = null) { $arr = String::tokenize($ctrlName, '/'); if (count($arr) == 2) { return $arr[0] . '.' . $arr[1]; } else { return $arr[0]; } } function _getPluginName($ctrlName = null) { $arr = String::tokenize($ctrlName, '/'); if (count($arr) == 2) { return $arr[0]; } else { return false; } } function _getPluginControllerName($ctrlName = null) { $arr = String::tokenize($ctrlName, '/'); if (count($arr) == 2) { return $arr[1]; } else { return false; } } /** * Get the names of the plugin controllers ... * * This function will get an array of the plugin controller names, and * also makes sure the controllers are available for us to get the * method names by doing an App::import for each plugin controller. * * @return array of plugin names. * */ function _getPluginControllerNames() { App::import('Core', 'File', 'Folder'); $paths = Configure::getInstance(); $folder =& new Folder(); $folder->cd(APP . 'plugins'); // Get the list of plugins $Plugins = $folder->read(); $Plugins = $Plugins[0]; $arr = array(); // Loop through the plugins foreach($Plugins as $pluginName) { // Change directory to the plugin $didCD = $folder->cd(APP . 'plugins'. DS . $pluginName . DS . 'controllers'); // Get a list of the files that have a file name that ends // with controller.php $files = $folder->findRecursive('.*_controller\.php'); // Loop through the controllers we found in the plugins directory foreach($files as $fileName) { // Get the base file name $file = basename($fileName); // Get the controller name $file = Inflector::camelize(substr($file, 0, strlen($file)-strlen('_controller.php'))); if (!preg_match('/^'. Inflector::humanize($pluginName). 'App/', $file)) { if (!App::import('Controller', $pluginName.'.'.$file)) { debug('Error importing '.$file.' for plugin '.$pluginName); } else { /// Now prepend the Plugin name ... // This is required to allow us to fetch the method names. $arr[] = Inflector::humanize($pluginName) . "/" . $file; } } } } return $arr; } ******************************************************************************** ### Create acos almos automaticly http://localhost/weblog/groups/build_acl ******************************************************************************** ### Setting up permissions cake/console/cake acl grant group.1 controllers all cake/console/cake acl deny group.2 controllers all cake/console/cake acl grant group.2 controllers posts ******************************************************************************** ### Setting up permissions, add to app/controllers/users_controller.php function initDB() { $group =& $this->User->Group; //Allow admins to everything $group->id = 1; $this->Acl->allow($group, 'controllers'); //allow managers to posts and widgets $group->id = 2; $this->Acl->deny($group, 'controllers'); $this->Acl->allow($group, 'controllers/Posts'); $this->Acl->allow($group, 'controllers/Widgets'); //allow users to only add and edit on posts and widgets $group->id = 3; $this->Acl->deny($group, 'controllers'); $this->Acl->allow($group, 'controllers/Posts/add'); $this->Acl->allow($group, 'controllers/Posts/edit'); $this->Acl->allow($group, 'controllers/Widgets/add'); $this->Acl->allow($group, 'controllers/Widgets/edit'); //we add an exit to avoid an ugly "missing views" error message echo "all done"; exit; } ******************************************************************************** ### Visit this link once http://localhost/weblog/users/initdb ******************************************************************************** ### In app/controllers/users_controller.php change beforeFilter ### In app/controllers/groups_controller.php change beforeFilter function beforeFilter() { parent::beforeFilter(); $this->Auth->allowedActions = array('index', 'view'); } ******************************************************************************** ### In app/app_controller.php add to beforeFilter $this->Auth->allowedActions = array('display'); ******************************************************************************** ### Cleanup * In app/app_controller.php remove build_acl, _getClassMethods, _isPlugin, _getPluginControllerPath, _getPluginName, _getPluginControllerName, _getPluginControllerNames functions * In app/controllers/users_controller.php remove initDB function ******************************************************************************** _BY: Pejman Moghadam_ _TAG: php, cakephp_ _DATE: 2011-11-15 18:03:09_