หลังจากที่ใช้ ACL กับ AuthComponent ได้แล้ว … ก็จะลองเปลี่ยนตัวอย่างเก่าให้ใช้ Group ได้ดู ก็แก้เยอะเหมือน :-P.
ผมเริ่มจากการแก้ database schema ก่อน. หลังจากที่ลองใช้ migration อยู่พักใหญ่แล้วผมก็งงๆ เลยตัดสินใจสละ table: aros และ users ไป.
เริ่มจากลบของใน table: aros และ aros_acos ก่อน ด้วยคำสั่ง:
mysql -u<your_username> -p<your_password> my_project -e 'delete from aros;'
mysql -u<your_username> -p<your_password> my_project -e 'delete from aros_acos;'
แล้วก็แก้ CakeSchema ของ user ใน folder: app/config/sql, ไฟล์: users.php แก้เป็นแบบนี้:
class UsersSchema extends CakeSchema {
var $name = 'users';
function before($event = array()) {
return true;
}
function after($event = array()) {
}
var $users =
array('id' => array('type'=>'integer',
'null' => false,
'key' => 'primary',
'extra' => 'auto_increment'),
'username' => array('type'=>'string',
'null' => false,
'length' => 255),
'password' => array('type'=>'string',
'null' => false,
'length' => 255),
'group_id' => array('type' => 'integer',
'null' => false),
'indexes' => array('PRIMARY' => array('column' => 'id',
'unique' => 1)));
var $groups =
array('id' => array('type' => 'integer',
'null' => false,
'key' => 'primary',
'extra' => 'auto_increment'),
'name' => array('type' => 'string',
'null' => 'false',
'length' => 255,
'unique' => true),
'parent_id' => array('type' => 'integer'),
'indexes' => array('PRIMARY' => array('column' => 'id',
'unique' => true),
'GRP_NAME_KEY' => array('column' => 'name',
'unique' => true)));
ของใหม่อีกอย่างหนึ่งในตัวอย่างนี้คือ AclBehavior ที่จะช่วย sync ระหว่าง users, groups และ acl. แต่เท่าที่ใช้มา AclBehavior ไม่แก้ค่า alias ใน Aro ก็เลยสร้าง AclaBehavior จากการดัดแปลง AclBehavior นิดๆ หน่อยๆ โดยเพิ่มไฟล์ acla.php ลงใน folder: app/model/behaviors แบบข้างล่าง (จริงแล้วต้องเปิด <?php และปิดด้วย ?> ด้วย … แต่ว่าใส่ใน wordpress แล้วเหมือนเพี้ยนๆ ผมก็แก้ไม่เป็นด้วย.)
/* SVN FILE: $Id: acl.php 6311 2008-01-02 06:33:52Z phpnut $ */
/**
* ACL behavior class.
*
* Enables objects to easily tie into an ACL system
*
* PHP versions 4 and 5
*
* CakePHP : Rapid Development Framework
* Copyright 2006-2008, Cake Software Foundation, Inc.
* 1785 E. Sahara Avenue, Suite 490-204
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright 2006-2008, Cake Software Foundation, Inc.
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
* @package cake
* @subpackage cake.cake.libs.model.behaviors
* @since CakePHP v 1.2.0.4487
* @version $Revision: 6311 $
* @modifiedby $LastChangedBy: phpnut $
* @lastmodified $Date: 2008-01-02 00:33:52 -0600 (Wed, 02 Jan 2008) $
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
/**
* Short description for file
*
* Long description for file
*
* @package cake
* @subpackage cake.cake.libs.model.behaviors
*/
class AclaBehavior extends ModelBehavior {
/**
* Maps ACL type options to ACL models
*
* @var array
* @access protected
*/
var $__typeMaps = array('requester' => 'Aro', 'controlled' => 'Aco');
/**
* Sets up the configuation for the model, and loads ACL models if they haven't been already
*
* @param mixed $config
*/
function setup(&$model, $config = array()) {
if (is_string($config)) {
$config = array('type' => $config);
}
$this->settings[$model->alias] = array_merge(array('type' => 'requester'), (array)$config);
$type = $this->__typeMaps[$this->settings[$model->alias]['type']];
if (!ClassRegistry::isKeySet($type)) {
uses('model' . DS . 'db_acl');
$object =& new $type();
} else {
$object =& ClassRegistry::getObject($type);
}
$model->{$type} =& $object;
if (!method_exists($model, 'parentNode')) {
trigger_error("Callback parentNode() not defined in {$model->alias}", E_USER_WARNING);
}
}
/**
* Retrieves the Aro/Aco node for this model
*
* @param mixed $ref
* @return array
*/
function node(&$model, $ref = null) {
$type = $this->__typeMaps[strtolower($this->settings[$model->alias]['type'])];
if (empty($ref)) {
$ref = array('model' => $model->alias, 'foreign_key' => $model->id);
}
return $model->{$type}->node($ref);
}
/**
* Creates a new ARO/ACO node bound to this record
*
* @param boolean $created True if this is a new record
*/
function afterSave(&$model, $created) {
if ($created) {
$type = $this->__typeMaps[strtolower($this->settings[$model->alias]['type'])];
$parent = $model->parentNode();
if (!empty($parent)) {
$parent = $this->node($model, $parent);
} else {
$parent = null;
}
$acl_node_alias = null;
if(method_exists($model, "aclNodeAlias"))
$acl_node_alias = $model->aclNodeAlias();
$model->{$type}->create();
$model->{$type}->save(array(
'parent_id' => Set::extract($parent, "0.{$type}.id"),
'model' => $model->alias,
'foreign_key' => $model->id,
'alias' => $acl_node_alias
));
}
}
/**
* Destroys the ARO/ACO node bound to the deleted record
*
*/
function afterDelete(&$model) {
$type = $this->__typeMaps[strtolower($this->settings[$model->alias]['type'])];
$node = Set::extract($this->node($model), "0.{$type}.id");
if (!empty($node)) {
$model->{$type}->delete($node);
}
}
}
ไม่พอก็ยังต้องแก้ CakeShell ต่อใน folder: app/vendors/shells
แก้ user.php:
uses ('controller'.DS.'components'.DS.'auth');
class UserShell extends Shell {
var $uses = array("User", "Group");
function add() {
$auth = new AuthComponent();
$username = $this->args[0];
$password = $auth->password($this->args[1]);
$grp_name = $this->args[2];
$grp = $this->get_group($grp_name);
$data = array("User" =>
array("username" => $username,
"password" => $password,
"group_id" => $grp["id"]));
if($this->User->save($data))
print "Success: $username was added\n";
else
print "Fail\n";
}
function get_group($name) {
$data = $this->Group->findByName($name);
if(!$data)
return null;
else
return $data["Group"];
}
}
สร้าง group.php ขึ้นมาใหม่:
class GroupShell extends Shell {
var $uses = array("Group", "Aro");
function add() {
$name = $this->args[1];
$parent_name = $this->args[0];
if($parent_name == '/')
$parent_id = null;
else
$parent_id = $this->get_parent($parent_name);
$data = array("Group" =>
array("parent_id" => $parent_id,
"name" => $name));
if($this->Group->save($data))
print "Success: group: $name has been added\n";
else
print "Fail\n";
}
function get_parent($name) {
$data = $this->Group->findByName($name, null, null, False);
if(!$data['Group']['id'])
return null;
else
return $data['Group']['id'];
}
}
ยังไม่หมดต้องมาแก้ model ต่อใน folder: app/model
แก้ user.php:
class User extends AppModel {
var $actsAs = array('Acla');
var $belongsTo = array('Group');
function parentNode() {
if(!$this->id)
return null;
$data = $this->read();
if(!$data['Group']['id'])
return null;
else
return array('model' => 'Group',
'foreign_key' => $data['Group']['id']);
}
}
ตามด้วยเขียน group.php ขึ้นมาใหม่:
class Group extends AppModel {
var $actsAs = array('Acla');
var $hasMany = array('User');
function parentNode() {
if(!$this->id)
return null;
$data = $this->read();
if(!$data['Group']['parent_id'])
return null;
else
return array('model' => 'Group',
'foreign_key' => $data['Group']['parent_id']);
}
function aclNodeAlias() {
if(!$this->id)
return null;
$data = $this->read();
if(!$data['Group']['name'])
return null;
else
return $data['Group']['name'];
}
}
จาก code ที่แก้มามากมายก็จะเริ่มเรียกใช้แล้ว. โดย cd เข้าไปใน cake/console สั่ง: ./cake schema run create users แล้วก็กด y ไปเรื่อยๆ. เพื่อที่จะ drop table: users เก่าทิ้งไป แล้วสร้าง table: users และ groups ขึ้นมาใหม่.
ตามด้วยสร้าง group ขึ้นมาใหม่แบ่งเป็น admins กับ users ตามนี้:
./cake group add ‘/’ users
./cake group add ‘/’ admins
แล้วก็ add user ไว้ทดลอง group ละ 1 user:
./cake user add myadmin mypassword admins
./cake user add myuser mypassword users
grant ให้ admins ดูได้ทั้ง site (ทุกหน้า, ทุก action):
./cake acl grant admins site ‘*’
grant ให้ users ดู Pages/display (เอาไว้ redirect มาเวลาดูหน้าอื่นไม่ได้). และ ดู Books/display1:
./cake acl grant users ‘Pages/display’ ‘*’
./cake acl grant users ‘Books/display1’ ‘*’
ถ้าลอง login ด้วย myadmin ก็จะดูได้ทุกหน้า. แต่ถ้า login ด้วย myuser ก็จะดู http://localhost/my_project/books/display2 ไม่ได้.
ก็เป็นอันว่า users แต่ละกลุ่ม ก็ดูหน้าเว็บได้ต่างๆ กันตามที่กำหมดไว้ :-).
อ้างอิง:
http://lemoncake.wordpress.com/2007/07/19/acl-with-groups/