We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

ACL in micro

Hi,

I need to implement an ACL in my micro app, which is the best way??

Thanks, Stefano



411
Accepted
answer
edited Apr '15

Hi Stefano,

Probably too late to help you, but just in case anyone else searches for this (as I did).

Most examples for ACL in Phalcon use controllers and views. In a Micro application there are no controllers or views. Here is a solution for a Micro framework using Collections (which help group handlers into Controllers)

//Create the ACL
$acl = new Phalcon\Acl\Adapter\Memory();

//The default action is DENY access
$acl->setDefaultAction(Phalcon\Acl::DENY);

/*
 * ROLES
 * Admin - can do anything
 * User - can do most things
 * Restricted User - read only
 * */
$acl->addRole(new Phalcon\Acl\Role('Guest'));
$acl->addRole(new Phalcon\Acl\Role('Restricted User'));
$acl->addRole(new Phalcon\Acl\Role('User'));
$acl->addRole(new Phalcon\Acl\Role('Admin'));

// User can do everything a Restricted User can do
$acl->addInherit('User','Guest');
$acl->addInherit('User','Restricted User');
// Admin can do everything a User and Restricted User can do
$acl->addInherit('Admin','Guest');
$acl->addInherit('Admin','Restricted User');
$acl->addInherit('Admin','User');

/*
 * RESOURCES
 * for each user, specify the 'controller' and 'method' they have access to (user=>[controller=>[method,method]],...)
 * this is created in an array as we later loop over this structure to assign users to resources
 * */
$arrResources = [
    'guest'=>[
        'Users'=>['register','login','resetRequest','resetUpdate'],
    ],
    'restrictedUser'=>[
        'Users'=>['readOne'],
    ],
    'user'=>[
        'Users'=>['update','delete'],
    ],
    'admin'=>[
        'Accounts' => ['upgrade','paymentHistory','invoices']
    ]
];

foreach($arrResources as $arrResource){
    foreach($arrResource as $controller=>$arrMethods){
        $acl->addResource(new Phalcon\Acl\Resource($controller),$arrMethods);
    }
}

/*
 * ACCESS
 * */
foreach ($acl->getRoles() as $objRole) {
    $roleName = $objRole->getName();

    //everyone gets access to global resources
    foreach ($arrResources['guest'] as $resource => $method) {
        $acl->allow($roleName,$resource,$method);
    }

    //restricted users
    if($roleName == 'Restricted User'){
        foreach ($arrResources['restrictedUser'] as $resource => $method) {
            $acl->allow($roleName,$resource,$method);
        }
    }

    //users
    if($roleName == 'User'){
        foreach ($arrResources['user'] as $resource => $method) {
            $acl->allow($roleName,$resource,$method);
        }
    }

    //admins
    if($roleName == 'Admin'){
        foreach ($arrResources['admin'] as $resource => $method) {
            $acl->allow($roleName,$resource,$method);
        }
    }
}

To check if a user has access to a controller/method you can call something like the following in a Middleware event or Application Event:

$app->before(function() use ($app,$acl) {
    //get the handler
    $arrHandler = $app->getActiveHandler();
    //get the controller for this handler (strip off the Controller namespace if required)
    $controller = str_replace('Controller\\','',get_class($arrHandler[0]));
    //is an Admin user allowed to view the current controller/method?
    $allowed = $acl->isAllowed('Admin', $controller, $arrHandler[1]);
    return $allowed;
});

Returning false cancels the route execution.



3.3k

Hi jkns,

Thank you, I've already implemented it and my solution is like yours :)

Thanks, Stefano

Hi Stefano,

Probably too late to help you, but just in case anyone else searches for this (as I did).

Most examples for ACL in Phalcon use controllers and views. In a Micro application there are no controllers or views. Here is a solution for a Micro framework using Collections (which help group handlers into Controllers)

//Create the ACL
$acl = new Phalcon\Acl\Adapter\Memory();

//The default action is DENY access
$acl->setDefaultAction(Phalcon\Acl::DENY);

/*
* ROLES
* Admin - can do anything
* User - can do most things
* Restricted User - read only
* */
$acl->addRole(new Phalcon\Acl\Role('Admin'));
$acl->addRole(new Phalcon\Acl\Role('User'));
$acl->addRole(new Phalcon\Acl\Role('Restricted User'));

/*
* RESOURCES
* for each user, specify the 'controller' and 'method' they have access to (user=>[controller=>[method,method]],...)
* this is created in an array as we later loop over this structure to assign users to resources
* */
$arrResources = [
   'global'=>[
       'Users'=>['register','readOne','resetRequest','resetUpdate','login'],
   ],
   'user'=>[
       'Users'=>['update','delete'],
   ],
   'admin'=>[
       'Accounts' => ['upgrade','paymentHistory','invoices']
   ]
];

foreach($arrResources as $arrResource){
   foreach($arrResource as $controller=>$arrMethods){
       $acl->addResource(new Phalcon\Acl\Resource($controller),$arrMethods);
   }
}

/*
* ACCESS
* */
foreach ($acl->getRoles() as $objRole) {
   $roleName = $objRole->getName();
   //everyone gets access to global resources
   foreach ($arrResources['global'] as $resource => $method) {
       $acl->allow($roleName,$resource,$method);
   }
   //admins get access to user resources as well as users
   if(in_array($roleName, ['Admin','User'])){
       foreach ($arrResources['user'] as $resource => $method) {
           $acl->allow($roleName,$resource,$method);
       }
   }
   //admin only resources
   if($roleName == 'Admin'){
       foreach ($arrResources['admin'] as $resource => $method) {
           $acl->allow($roleName,$resource,$method);
       }
   }
}

To check if a user has access to a controller/method you can call something like the following in a Middleware event or Application Event:

$app->before(function() use ($app,$acl) {
   //get the handler
   $arrHandler = $app->getActiveHandler();
  //get the controller for this handler (strip off the Controller namespace if required)
   $controller = str_replace('Controller\\','',get_class($arrHandler[0]));
  //is an Admin user allowed to view the current controller/method?
   $allowed = $acl->isAllowed('Admin', $controller, $arrHandler[1]);
   return $allowed;
});

Returning false cancels the route execution.



411

No worries. Glad you got it soerted. If we implemented the same thing it must be right!

Jkns

Hi jkns,

Thank you, I've already implemented it and my solution is like yours :)

Thanks, Stefano



3.3k

Absolutely! It works very well, good job ;)

No worries. Glad you got it soerted. If we implemented the same thing it must be right!

Jkns

Hi jkns,

Thank you, I've already implemented it and my solution is like yours :)

Thanks, Stefano