Simple access control

  1. Considerations
  2. Implementation
  3. Final words

For those who feel, the Controller->accessRules() or RBAC (Role-Based Access Control) is too complicated or doesn't want the username(s) to be hard-coded in accessRules(), here is a very simple, easy-to-implement solution.

Considerations

As usual, you will have a table, holding the user's data, such as: username, password, email, real_name, etc. To store the user rights, you need an additional field, named admin_level. This will be an unsigned tinyint, and will hold the user's rights to do things around the site. You will define the admin levels, according to your needs. Now, for this example, let's define 4 levels: 0: REGULAR_USER - basic access 1: EDITOR - access to product editing, translations, etc. 2: MANAGER - Higher level control: site settings, statistics, etc. 3: ADMIN - Delete/modify users, modify critical site settings, handle money, etc.

Implementation

Step 1. Create/modify the user table:
[sql]
CREATE TABLE `users` (
	`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
	`username` varchar(25) CHARACTER SET ascii NOT NULL,
	`password` varchar(128) COLLATE utf8_bin NOT NULL,
	`email` varchar(100) COLLATE utf8_bin NOT NULL,
	`admin_level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0: regular user; 1: editor; 2: manager; 3: admin'
)
Step 2. Create the user login-logout mechanism

Following the standard, recommended procedure, you will have a login-logout functionality.

Step 3. Define the user levels and create the access-control functionality.

Open the protected/components/Controller.php file and add the following to the beginning of the file:

define('REGULAR_USER', 0);
define('EDITOR', 1);
define('MANAGER', 2);
define('ADMIN', 3);

You will load and store the user's data every time a page is requested. To do this, modify the Controller class as follows:

Add a userData property:

public $userData; // Holds an activeRecord with current user. NULL if guest

Define (or extend) the init() function:

public function init() {
	...
	// Load the user
	if (!Yii::app()->user->isGuest)
		$this->userData = AR_Users::model()->findByPk(Yii::app()->user->id);
	...
}

Add the allowUser function:

public function allowUser($min_level) { //-1 no login required 0..3: admin level
	$current_level = -1;
	if ($this->userData !== null)
		$current_level = $this->userData->admin_level;
	if ($min_level > $current_level) {
		throw new CHttpException(403, 'You have no permission to view this content');
	}
}
Step 4. Begin your controller actions calling the allowUser() function.

If the current user will not have the required admin level, a CHttpException will be thrown. If you don't need any access control, don't use the allowUser() function.

class SomeController extends Controller {

	public function actionIndex() {
		// $this->allowUser(REGULAR_USER); // everybody can view index
		$this->render('index');
	}

	public function actionLogin() {
		// $this->allowUser(REGULAR_USER); // everybody can log in
		$this->render('login', array(...));
	}

	public function actionEditproduct($id) {
		$this->allowUser(EDITOR); // only editors, managers and admins can edit products
		...
		$this->render('editproduct', array(...));
	}

	public function actionSitesettings($id) {
		$this->allowUser(MANAGER); // only managers and admins can change site settings
		...
		$this->render('sitesettings', array(...));
	}

	public function actionEdituser($id) {
		$this->allowUser(ADMIN); // only admins can change user data
		...
		$this->render('edituser', array(...));
	}

}

Final words

  • you can use the userData property to check, display or even modify user data. If userData === null, there is no user logged in, so you need to check first this.
  • the userData->admin_level can be edited along with the other user data, so everybody's rights can be changed (by an admin)
  • the user rights will be hard-coded. This will help not tech-guru site owners to manage their subscribed members, especially to allow/disallow employees to do/see certain tasks on the site.