cakephp中acl详解.docx
《cakephp中acl详解.docx》由会员分享,可在线阅读,更多相关《cakephp中acl详解.docx(15页珍藏版)》请在冰豆网上搜索。
cakephp中acl详解
cakephp中acl和auth详解
2009-11-10,auther:
kenny,
自学习cakephp以来,一直没有完成搞懂acl,对它的用法也是一知半解,acl应该是cakephp中一个比较难懂的地方,这几天又重新看了下手册,发现acl没有相信中的难,但比我想象中的好用
下面让我说说它的具体用法已经使用过程中应该注意到问题
准备前工作:
最好是能配置好bake,使bake命名有效,虽然这个不是必须的,不过有这个命令行工具以后我们会方便很多
在你的数据库中导入下面的sql语句
CREATETABLEusers(
idINT(11)NOTNULLAUTO_INCREMENTPRIMARYKEY,
usernameVARCHAR(255)NOTNULLUNIQUE,
passwordCHAR(40)NOTNULL,
group_idINT(11)NOTNULL,
createdDATETIME,
modifiedDATETIME
);
CREATETABLEgroups(
idINT(11)NOTNULLAUTO_INCREMENTPRIMARYKEY,
nameVARCHAR(100)NOTNULL,
createdDATETIME,
modifiedDATETIME
);
CREATETABLEposts(
idINT(11)NOTNULLAUTO_INCREMENTPRIMARYKEY,
user_idINT(11)NOTNULL,
titleVARCHAR(255)NOTNULL,
bodyTEXT,
createdDATETIME,
modifiedDATETIME
);
CREATETABLEwidgets(
idINT(11)NOTNULLAUTO_INCREMENTPRIMARYKEY,
nameVARCHAR(100)NOTNULL,
part_noVARCHAR(12),
quantityINT(11)
);
在这里我们使用cakebakeall命令工具快速生成models,controllers,和views(在这里我就详细介绍怎么使用cakephp中的bake命令了)
下一步,准备使用auth组件认证
首先我们打开users_controller.php在UsersController类中增加登录登出动作
functionlogin(){
//AuthMagic
}
functionlogout(){
//Leaveemptyfornow.
}
然后创建视图文件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
classAppControllerextendsController{
var$components=array('Acl','Auth');
functionbeforeFilter(){
//ConfigureAuthComponent
$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');
}
}
?
>
接下来我们需要修改GroupsController和UsersController,这两个文件的目录大家应该都知道在哪里吧..
在这两个控制器中分别添加以下代码
functionbeforeFilter(){
parent:
:
beforeFilter();
$this->Auth->allowedActions=array('*');
}
其实这段代码的意思是允许用户访问所有user和group下的action,当然这个后面是要改回来的
接下来我们要初始化acl表
因为现在我们的数据库中就只有四个表,还没有导入acl表
我们用下面语句导入acl表到数据库中
在命令行中输入cakeschemaruncreateDbAcl
我们根据提示导入表
接下来我们需要修改user和group模型
首先我们打开model目录下的user.php增加以下代码(事实上你可以用下面代码替换)
var$name='User';
var$belongsTo=array('Group');
var$actsAs=array('Acl'=>'requester');
functionparentNode(){
if(!
$this->id&&empty($this->data)){
returnnull;
}
$data=$this->data;
if(empty($this->data)){
$data=$this->read();
}
if(!
$data['User']['group_id']){
returnnull;
}else{
returnarray('Group'=>array('id'=>$data['User']['group_id']));
}
}
然后修改group模型
var$actsAs=array('Acl'=>array('requester'));
functionparentNode(){
returnnull;
}
好了,到这一步我们需要暂时停一下了,现在在浏览器中打开相应的user和group页面,增加user和group,比如我的,我打开http:
//localhost/cakephp/groups增加组,打开http:
//localhost/cakephp/users/增加用户,在这里我们增加三个组和三个用户
添加完以后你可以打开phpmyadmin看下aros表看下是不是多了些记录
是不是觉得很神奇不可思议啊,哈哈,这就是框架的魅力,到目前为止和acl有关的表,就只有aros表中存在记录
在我们以后修改每一个user用户时,我们也必须修改aros表记录
所有我们应该做user模型中增加下面代码
/**
*Aftersavecallback
*
*Updatethearofortheuser.
*
*@accesspublic
*@returnvoid
*/
functionafterSave($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的组件,明白了这一点一切就变的很简单了。
为了简单我们使用命令行执行cakeaclcreateacorootcontrollers
你现在再用phpmyadmin打开acors表,你应该会看到表中已经有一条记录了,这条记录就是刚刚执行这个命令的结果,当然我们不一定非得用命令行工具的。
接下来我们还需要修改下AppController,在里面的beforeFilter方法中我们需要增加一行$this->Auth->actionPath='controllers/';
下面是重点,在我们的app项目中可能会存在很多的控制器和方法,我们需要把每个action都添加到acors表中来实现权限控制,当然如果你不怕麻烦的话可以一个一个手动添加,但我想大多数程序员还是很懒的,所有我们这里需要使用自动生成工具
这里我们添加下面代码放在users_controller.php中,当然你也可以放在其他的控制器中
下面我就在users_controller.php中增加下面代码
functionbuild_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[]='CreatedAconodeforcontrollers';
}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);
//lookateachcontrollerinapp/controllers
foreach($Controllersas$ctrlName){
$methods=$this->_getClassMethods($this->_getPluginControllerPath($ctrlName));
//DoallPluginsFirst
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[]='CreatedAconodefor'.$this->_getPluginName($ctrlName).'Plugin';
}
}
//find/makecontrollernode
$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[]='CreatedAconodefor'.$this->_getPluginControllerName($ctrlName).''.$this->_getPluginName($ctrlName).'PluginController';
}else{
$aco->create(array('parent_id'=>$root['Aco']['id'],'model'=>null,'alias'=>$ctrlName));
$controllerNode=$aco->save();
$controllerNode['Aco']['id']=$aco->id;
$log[]='CreatedAconodefor'.$ctrlName;
}
}else{
$controllerNode=$controllerNode[0];
}
//cleanthemethods.toremovethoseinControllerandprivateactions.
foreach($methodsas$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[]='CreatedAconodefor'.$method;
}
}
}
if(count($log)>0){
debug($log);
}
}
function_getClassMethods($ctrlName=null){
App:
:
import('Controller',$ctrlName);
if(strlen(strstr($ctrlName,'.'))>0){
//plugin'scontroller
$num=strpos($ctrlName,'.');
$ctrlName=substr($ctrlName,$num+1);
}
$ctrlclass=$ctrlName.'Controller';
$methods=get_class_methods($ctrlclass);
//Addscaffolddefaultsifscaffoldsarebeingused
$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){
returntrue;
}else{
returnfalse;
}
}
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{
returnfalse;
}
}
function_getPluginControllerName($ctrlName=null){
$arr=String:
:
tokenize($ctrlName,'/');
if(count($arr)==2){
return$arr[1];
}else{
returnfalse;
}
}
/**
*Getthenamesoftheplugincontrollers...
*
*Thisfunctionwillgetanarrayoftheplugincontrollernames,and
*alsomakessurethecontrollersareavailableforustogetthe
*methodnamesbydoinganApp:
:
importforeachplugincontroller.
*
*@returnarrayofpluginnames.
*
*/
function_getPluginControllerNames(){
App:
:
import('Core','File','Folder');
$paths=Configure:
:
getInstance();
$folder=&newFolder();
$folder->cd(APP.'plugins');
//Getthelistofplugins
$Plugins=$folder->read();
$Plugins=$Plugins[0];
$arr=array();
//Loopthroughtheplugins
foreach($Pluginsas$pluginName){
//Changedirectorytotheplugin
$didCD=$folder->cd(APP.'plugins'.DS.$pluginName.DS.'controllers');
//Getalistofthefilesthathaveafilenamethatends
//withcontroller.php
$files=$folder->findRecursive('.*_controller\.php');
//Loopthroughthecontrollerswefoundinthepluginsdirectory
foreach($filesas$fileName){
//Getthebasefilename
$file=basename($fileName);
//Getthecontrollername
$file=Inflector:
:
camelize(substr($file,0,strlen($file)-strlen('_controller.php')));