文档章节

cakephp中acl和auth详解

Adam-Lee
 Adam-Lee
发布于 2011/06/01 10:00
字数 2337
阅读 2.5K
收藏 1

自学习cakephp以来,一直没有完全搞懂acl,对它的用法也是一知半解,acl应该是cakephp中一个比较难懂的地方,这几天又重新看了下手册,发现acl也没有相像中那么的难,但比我想象中的好用

下面让我说说它的具体用法以及使用过程中应该注意到问题

准备前工作:

最好是能配置好bake,使bake命名有效,虽然这个不是必须的,不过有这个命令行工具以后我们会方便很多

在你的数据库中导入下面的sql语句

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)

);

 

在这里我们使用cake bake all命令工具快速生成models, controllers, views(在这里我就详细介绍怎么使用cakephp中的bake命令了)

下一步,准备使用auth组件认证

首先我们打开users_controller.phpUsersController类中增加登录登出动作

 

 

 

 

 

function login() {
    //Auth Magic
}
 
function logout() {
    //Leave empty for now.
}

然后创建视图文件app/views/users/login.ctp

<?php

$session->flash('auth');

echo $form->create('User', array('action' => 'login'));

echo $form->inputs(array(

         'legend' => __('Login', true),

         'username',

         'password'

));

echo $form->end('Login');

 

?>

下一步我们需要修改AppController(/app/app_controller.php),如果你的app目录下面没有app_controller.php文件的话,你可以自己创建一个

<?php
class AppController extends Controller {
    var $components = array('Acl', 'Auth');
 
    function beforeFilter() {
        //Configure AuthComponent
        $this->Auth->authorize = 'actions';
        $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
        $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
        $this->Auth->loginRedirect = array('controller' => 'posts', 'action' => 'add');
    }
}
?>

 

接下来我们需要修改GroupsControllerUsersController,这两个文件的目录大家应该都知道在哪里吧..

在这两个控制器中分别添加以下代码

 

 

 

function beforeFilter() {
    parent::beforeFilter(); 
    $this->Auth->allowedActions = array('*');
}

 

其实这段代码的意思是允许用户访问所有usergroup下的action,当然这个后面是要改回来的

 

接下来我们要初始化acl

因为现在我们的数据库中就只有四个表,还没有导入acl

我们用下面语句导入acl表到数据库中

在命令行中输入cake schema run create DbAcl

我们根据提示导入表

 

接下来我们需要修改usergroup模型

首先我们打开model目录下的user.php增加以下代码(事实上你可以用下面代码替换)

var $name = 'User';
var $belongsTo = array('Group');
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 (!$data['User']['group_id']) {
        return null;
    } else {
        return array('Group' => array('id' => $data['User']['group_id']));
    }
}

然后修改group模型

 

var $actsAs = array('Acl' => array('requester'));
 
function parentNode() {
    return null;
}

 

 

好了,到这一步我们需要暂时停一下了,现在在浏览器中打开相应的usergroup页面,增加usergroup,比如我的,我打开http://localhost/cakephp/groups增加组,打开http://localhost/cakephp/users/ 增加用户,在这里我们增加三个组和三个用户

 

添加完以后你可以打开phpmyadmin看下aros表看下是不是多了些记录

是不是觉得很神奇不可思议啊,哈哈,这就是框架的魅力,到目前为止和acl有关的表,就只有aros表中存在记录

 

在我们以后修改每一个user用户时,我们也必须修改aros表记录

所有我们应该做user模型中增加下面代码

/**    
 * 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);
        }
}

 

到这里我们aro创建已经完成,接下来我们应该创佳aco

我们应该知道其实acl的本质是用来定义一个ARO在什么时候可以访问一个aco的组件,明白了这一点一切就变的很简单了

为了简单我们使用命令行执行cake acl create aco root controllers

你现在再用phpmyadmin打开acors表,你应该会看到表中已经有一条记录了,这条记录就是刚刚执行这个命令的结果,当然我们不一定非得用命令行工具的。

 

接下来我们还需要修改下AppController,在里面的beforeFilter方法中我们需要增加一行$this->Auth->actionPath = 'controllers/';

 

下面是重点,在我们的app项目中可能会存在很多的控制器和方法,我们需要把每个action都添加到acors表中来实现权限控制,当然如果你不怕麻烦的话可以一个一个手动添加,但我想大多数程序员还是很懒的,所有我们这里需要使用自动生成工具

 

这里我们添加下面代码放在users_controller.php中,当然你也可以放在其他的控制器中

下面我就在users_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 = Configure::listObjects('controller');
               $appIndex = array_search('App', $Controllers);
               if ($appIndex !== false ) {
                       unset($Controllers[$appIndex]);
               }
               $baseMethods = get_class_methods('Controller');
               $baseMethods[] = 'buildAcl';
 
               $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;
        }

 

 

增加好以后我们打开浏览器访问刚才的方法

比如我的http://localhost/cakephp/users/build_acl

运行后程序会自动把所有controller下的action都添加到acos表中,你现在打开acos表应该就会看到很多记录了,如

 

接下来应该是做我们最兴奋的事情了,就是实现权限控制,因为我们前期准备工作都做好了,最终我们都是为了实现可以控制权限

 

  1. 先来介绍下语法,允许访问$this->Acl->allow($aroAlias, $acoAlias);

拒绝访问$this->Acl->deny($aroAlias, $acoAlias);

 

你先打开aros_acos表中看下,到目前为止该表应该还是没有记录的

我们可以写一个初始化函数

我同样把这段代码放在user控制器中

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');
}

 

接下来我们在浏览器中访问这个action

 

这个是时候你就应该发现你的aros_acos表中多了很多条记录,哈哈,这个就是acl的秘密所在.

 

接下来你可以使用不同组的用户名登录访问,你还可以修改initDB里面的代码进行测试,至于实际工作中如何使用,那就要看你自己的了,最后祝大家工作愉快!

© 著作权归作者所有

Adam-Lee
粉丝 50
博文 118
码字总数 166965
作品 0
深圳
程序员
私信 提问
加载中

评论(1)

今晚月亮好美
今晚月亮好美
0写的很详细
Tasks for new employees(Junior Programmers)

Jquery方面: 1) 用Jquery实现单击按纽1可以选中所有页面上的checkbox,单击按纽2可取消对所有checkbox的选择,单击按纽3可以获得页面上所有选中的checkbox的值; 2) 用Jquery实现点击一个按...

Adam-Lee
2011/09/22
135
0
CakePHP 2.0 发布,PHP的Web应用框架

CakePHP开发团队已经发布了CakePHP 2.x系列的一个版本CakePHP 2.0。在该版本中不再支持PHP4,CakePHP团队对其代码库进行了重构,以便严格遵循PHP 5规范(包括5.2及以后版本)。 CakePHP是一个...

鉴客
2011/10/19
2.3K
2
CakePHP 3.4.0 和 3.3.15 发布,PHP 开发框架

CakePHP 核心团队很高兴地宣布 CakePHP 3.4.0 和 3.3.15 发布了,CakePHP 是一个 PHP 的快速开发框架,使用常见的设计模式,如关联数据映射、前端控制器和 MVC。 主要目标是提供一个结构化框...

两味真火
2017/02/13
1.1K
3
在 Windows Azure 网站上运行 CakePHP 应用

上周我搞了个简单的 CakePHP 应用并在 Windows Azure 上跑了起来。 CakePHP是一个运用了诸如ActiveRecord、Association Data Mapping、Front Controller和MVC等著名设计模式的快速开发框架。...

红薯
2012/08/02
1.9K
4
wamp下配置cakePHP(可解决不加载样式问题)

CakePHP的安装很简单只需要下载代码包到自己的服务器目录就可以了。 我用的是Wamp环境,配置步骤如下: 1.下载CakePHP,地址:“https://codeload.github.com/cakephp/cakephp/legacy.zip/...

梦梦阁
2018/04/23
20
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql中int(11)的列大小是多少?

mysql中int(11)的列大小是多少? 以及可以在此列中存储的最大值? #1楼 mysql中int(11)的列大小是多少? (11) int数据类型的此属性与列的大小无关。 它只是整数数据类型的显示宽度。 从11....

技术盛宴
33分钟前
37
0
聊聊artemis消息的推拉模式

序 本文主要研究一下artemis消息的推拉模式 拉模式 receive activemq-artemis-2.11.0/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMessageConsumer.......

go4it
42分钟前
39
0
vue 全局前置守卫引起死循环的原因与解决方法

我们经常会用到全局前置守卫,如判断用户有没有登陆过,如果登陆过就直接跳到目的页面,如果没有登陆过,就跳转到登陆页。 先看官网对全局前置守卫的介绍 使用 router.beforeEach 注册一个全...

tianyawhl
54分钟前
31
0
如何按索引从std :: vector <>擦除元素?

我有一个std :: vector <int>,我想删除第n个元素。 我怎么做? std::vector<int> vec;vec.push_back(6);vec.push_back(-17);vec.push_back(12);vec.erase(???); #1楼 erase方法将以两......

javail
今天
43
0
使用生成器模拟时间分片

对于cpu密集型任务, 时间分片可以有效减少页面卡顿, 不过对于纯计算型任务还是推荐使用worker在后台做计算 效果图, 计算密集型任务被分到每次只执行16ms, 每次执行完毕留给浏览器时间去响应事...

阿豪boy
今天
63
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部