Page 1 of 1

CodeIgniter framework, roles management

Posted: Wed Apr 23, 2008 9:56 am
by VladSun
Hello, CodeIgniters :)
I am working on a relatively big project with a lot of controllers and actions and unknown number of user roles. I've decided to use CodeIgniter framework.
The first problem that I faced was the implementation of user authorization and his role permissions logic.
I wrote a solution that works pretty good for me, but I need your criticism, so I can make it better and continue to use it in future projects cleanly.

So ... in /system/codeigniter/CodeIgniter.php I change this code:

Code: Select all

 
        // Call the requested method.
        // Any URI segments present (besides the class/function) will be passed to the method for convenience       
        call_user_func_array(array(&$CI, $method), array_slice($RTR->rsegments, (($RTR->fetch_directory() == '') ? 2 : 3)))
to

Code: Select all

 
        if (method_exists($CI, '_check_privileges'))
        {
            if ($CI->_check_privileges($class, $method))
            {
                // Call the requested method.
                // Any URI segments present (besides the class/function) will be passed to the method for convenience       
                call_user_func_array(array(&$CI, $method), array_slice($RTR->rsegments, (($RTR->fetch_directory() == '') ? 2 : 3)));        
            }
        }
        else
        {
            // Call the requested method.
            // Any URI segments present (besides the class/function) will be passed to the method for convenience       
            call_user_func_array(array(&$CI, $method), array_slice($RTR->rsegments, (($RTR->fetch_directory() == '') ? 2 : 3)));        
        }
I create a new base class for Controller (simplified version, no error reporting, etc.):

Code: Select all

 
class CC_Controller extends Controller 
{
    var $is_login = false;
    
    function CC_Controller($is_login = false)
    {
        parent::Controller();
        
        $this->is_login = $is_login;
        $this->user_logged = empty($_SESSION) ? false : (!empty($_SESSION['user_id']) ? true : false);
    }
    
    function _check_privileges($object = null, $method = null)
    {
        // Populate object/method values
        $this->object = $object;
        $this->method = $method;
        
        // Only login controller should set $is_login to true
        if ($this->is_login)
            return true;
            
        // Obviously user could not be granted any permissions when not logged in 
        if (!$this->user_logged)
            return false;
 
        if (empty($object) || empty($method))
            return false;
 
        // Role model should return 2D Array of object/methods
        $this->load->model('role_model', '_role');
        $this->role_permissions = $this->_role->get_permissions($_SESSION['user_role']);
 
        // Role not found
        if (empty($this->role_permissions))
            return false;
 
        // Permission to access this controller not granted 
        if (empty($this->role_permissions[strtolower($object)]))
            return false;
 
        // Permission to access this action of the controller not granted 
        if (empty($this->role_permissions[strtolower($object)][strtolower($method)]))
            return false;
 
        // OK
        return true;
    }
}
 
Every controller in my application folder must extend the CC_Controller class.

Any comments are welcome :)

PS: Maybe implementing a group role permissions is a good idea, but I think it should be placed in the Model, transparently to the CC_Controller ($_SESSION['user_id'] should be passed to get_permissions()?).

Re: CodeIgniter framework, roles management

Posted: Wed Apr 23, 2008 4:27 pm
by Gruessle
CodeIgnitor is great. I had the same problem when I created my CI side.
Lately I been checking in to Zend framework and I have a suggestion for you.

If you have already coded a lot in CI and don't wont to switch. You can always use Zend components within CI.
Zend has a great authentication class and ACL class. You don't have to use all of ZF you can just use those classes within CI.

Here is an example for ZF ACL, which will work standalone.

Code: Select all

 
require_once 'Acl.php';
$acl = new Tamer_ACL();
$acl->aclCreate();
 
echo 'Guest view: ';
echo $acl->isAllowed('guest', null, 'view') ? "allowed" : "denied";
 
echo 'Guest edit: ';
echo  $acl->isAllowed('guest', null, 'edit') ? "allowed" : "denied";
 
 
File Acl.php

Code: Select all

<?php
require_once 'Zend/Acl.php';
require_once 'Zend/Acl/Role.php';
require_once 'Zend/Acl/Resource.php';
 
class Tamer_ACL extends Zend_ACL 
{
    function aclCreate()
    {
        $this->addRole(new Zend_Acl_Role('guest'));
        //$this->deny('guest', null, 'view');
        
        $this->addRole(new Zend_Acl_Role('member'));
        $this->allow('member', null, array('view'));
        
        // Administrator does not inherit access controls
        $this->addRole(new Zend_Acl_Role('admin'), 'member');
        $this->allow('admin', null, array('add', 'edit', 'delete'));
        
        $this->add(new Zend_Acl_Resource('adminArea'));
        $this->add(new Zend_Acl_Resource('jobsearch'));
    }
}
?>

Re: CodeIgniter framework, roles management

Posted: Wed Apr 23, 2008 4:53 pm
by VladSun
Thanks for answering :)

As far as I can understand it, the Acl.php is equal to my Role_Model file :) I didn't want to show its code because one may use a different storage. In my case I used DB storage and wrote a controller to manage roles, role rules and role rule permissions :)

The main problem was where to put the role control implementation - as you see I modified the CI core files, because I wasn't able to find a better insert point.

I think it works pretty good, because the descendant controller don't care about it - it's fully transparent for them.