Aug
22

Sử dụng Acl trong cakephp – Phần 2

Author admin    Category Chia sẻ, Tutorial     Tags

Chúng ta tiếp tục phần 2 của bài viết “Sử dụng Acl trong cakephp”

6. Kiếm tra xem group và user đã được liên kết với Acl chưa

- Các bạn mở trình duyệt và chạy url: http://localhost/cake_acl/groups/add
- Lần lượt thêm vào các group: Administrators, Managers và Users
- Chạy tiếp url: http://localhost/cake_acl/users/add
- Thêm vào các user: admin (thuộc group Administrators), manager (thuộc group Managers), user (thuộc group Users). Nhớ password đã đặt cho từng user
(Đường link của các bạn có thể khác của mình)
- Sau khi đã thêm các group và user như trên, bạn mở bảng aros ra và xem dữ liệu:

aros

- Nếu dữ liệu ra đúng như trên thì AclBehavior đã hoạt động đúng

7. Tạo aco

- Bước tiếp theo, chúng ta sẽ đưa tất cả các controller (bao gồm cả đối tượng cotrollers), các action của từng controller vào bảng acos
- Để công việc này thuận tiện hơn, chúng ta sẽ sử dụng đoạn code đã được xây dựng sẵn. Bạn đưa đoạn code dưới vào controller nào cũng được, mình đưa vào groups_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;
}

- Mở trình duyệt lên và chạy: http://localhost/cake_acl/groups/build_acl
- Mở bảng acos để xem dữ liệu:

acos

- Chèn code sau vào trong hàm beforeFilter của app_controller.php

$this->Auth->actionPath = 'controllers/';

8. Phân quyền

- Cú pháp chung:

$this->Acl->allow($aroAlias, $acoAlias);

- Phân quyền demo: đưa hàm bên dưới vào users_controller.php

function initDB() {
    $group =& $this->User->Group;
    //cho phép administrators truy cập mọi thứ
    $group->id = 1;     
    $this->Acl->allow($group, 'controllers');
 
    //cho phép managers quản lý post, cấm truy xuất khu vực và action khác
    $group->id = 2;
    $this->Acl->deny($group, 'controllers');
    $this->Acl->allow($group, 'controllers/Posts');
 
    //cho phép users chỉ được add và edit post, cấm truy xuất các khu vực và action khác
    $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');
 
    echo "all done";
    exit;
}

- Mở trình duyệt lên và chạy: http://localhost/cake_acl/users/initDB
- Mở bảng aros_acos xem dữ liệu:

aros_acos

- Như vậy là phân quyền thành công

9. Kiểm thử

- Bỏ hàm beforeFilter() trong groups_controller.php và users_controller.php đi
- Mở trình duyệt chạy link: http://localhost/cake_acl/users/, bạn sẽ bị đẩy ra trang login. Tại đây bạn tiến hành đăng nhập lần lượt bằng các user: admin, manager và user, sau đó thao tác với các action trong group, user và post.
- Nếu vào action nào không được phép, bạn sẽ bị redirect về trang đã đứng trước đó!

10. Chúc các bạn thực hiện thành công

- Các bạn có thể tải các file liên quan tới bài viết tại đây: hướng dẫn dùng Acl và Auth trong cakephp

Chú ý: khi đưa ứng dụng lên hosting các bạn phải remove 2 function build_acl và initDB đi nhé!

1 Comment to “Sử dụng Acl trong cakephp – Phần 2”

  • mrzii 29/03/2011 at 9:52 am

    Notice (8): Undefined property: UsersController::$Acl [APP\controllers\users_controller.php, line 27]
    Fatal error: Call to a member function allow() on a non-object in C:\xampp\htdocs\loginacl\app\controllers\users_controller.php on line 27

    Mình copy source của bạn chạy thử nhưng mà khi chạy đến bước xuất dữ liệu cho table aco thì bị lỗi như vậy.

Post comment

Follow us on Twitter! Follow us on Twitter!
Diễn đàn CakePHP cho người Việt Nam

Bài viết mới

Thảo luận mới

TAG

Calendar

August 2010
M T W T F S S
« Jul   Sep »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Lưu trữ

Blogroll

Thống kê

Danh sách: 5 khách