The examples on this site are currently tested to work on Phalcon V3.4 and Phalcon Devtools V3.2 Some issues may arise when using later versions.

Please get in touch or post a comment below the post if you encounter a problem.

Now that the roles, resources, actions and access control list are stored in the database we need to modify the Security Plugin to use this information rather than hard-coding this information directly into the Security Plugin PHP file itself. The script below is a modified version of the SecurityPlugin from the Phalcon Invo application. This version of the script reads roles, resources, actions and an accesscontrollist from the database and sets it up to be stored as a persistent $acl variable. Once this file is up and running it should not be necessary to modify it. The script should be saved as SecurityPlugin.php and saved to apps/plugins (you may have to create a plugins folder).

<?php

use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Resource;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Acl\Adapter\Memory as AclList;
use security\Dbaccesscontrollist;
use security\Dbresource;
use security\Dbaction;
use security\Dbrole;
/**
 * SecurityPlugin
 *
 * This is the security plugin which controls that users only have access to the modules they're assigned to
 */
class SecurityPlugin extends Plugin
{
    /**
     * Returns an existing or new access control list
     *
     * @returns AclList
     */
    public function getAcl()
    {
        
        if (!isset($this->persistent->acl)) {

            $acl = new AclList();

            $acl->setDefaultAction(Acl::DENY);
                
            $dbRoles = DBRole::find();
            $dbResources = DBResource::find();
            $dbACLItems = DBaccesscontrollist::find();
            
            // Register roles
            foreach($dbRoles as $dbRole) {
                $acl->addRole($dbRole->getRole());
            }
            
            foreach($dbResources as $dbResource) {
                $dbActions = $dbResource->getDbaction();
                $actions[] = null;
                foreach($dbActions as $dbAction) {
                    array_push($actions,$dbAction->getAction());
                }
                $acl->addResource(new Resource($dbAction->getResource()),$actions);
            }
            
            foreach ($dbACLItems as $ACLItem){
                $acl->allow($ACLItem->getRole(), $ACLItem->getResource(), $ACLItem->getAction());
            }
            
            //The acl is stored in session, APC would be useful here too
            $this->persistent->acl = $acl;
        }

        return $this->persistent->acl;
    }

    /**
     * This action is executed before execute any action in the application
     *
     * @param Event $event
     * @param Dispatcher $dispatcher
     * @return bool
     */
    public function beforeDispatch(Event $event, Dispatcher $dispatcher)
    {

        $auth = $this->session->get('auth');
        if (!$auth){
            $role = 'Guest'; 
        } else {
            $role = $auth['role'];
        }

        $controller = strtolower($dispatcher->getControllerName());
        $action = strtolower($dispatcher->getActionName());

        $acl = $this->getAcl();
        if (!$acl->isResource($controller)) {
            $dispatcher->forward([
                'controller' => 'errors',
                'action'     => 'show404'
            ]);

            return false;
        }
        
        $allowed = $acl->isAllowed($role, $controller, $action);
        if (!$allowed) {
            $dispatcher->forward(array(
                'controller' => 'errors',
                'action'     => 'show401'
            ));
            return false;
        }
    }
}
?>

To get your application to see the SecurityPlugin in the plugins folder you must add the plugins folder to the register of folders that phalcon uses. The location of pluginsDir is already set in app/config/config.php  To add the pluginsDir to the register add a line of code to the app/config/loader.php file as indicated in the following screenshot:

To get the Security Plugin working you need to add some code to the app/config/services.php file. Firstly you need to add the following three use statements at the top of the services.php file to allow these components to be seen.

use Phalcon\Mvc\Dispatcher as Dispatcher;
use Phalcon\Events\Manager as EventsManager;

Add the following lines at the bottom of app/config/services.php to add the EventsManager and the Dispatcher to the dependency injector container which allows them to be registered as services.

/*
$di->set('dispatcher', function () use ($di) {
	$eventsManager = new EventsManager;
	//Check if the user is allowed to access certain action using the SecurityPlugin
	$eventsManager->attach('dispatch:beforeDispatch', new SecurityPlugin);
	//Handle exceptions and not-found exceptions using NotFoundPlugin
	//$eventsManager->attach('dispatch:beforeException', new NotFoundPlugin);
	$dispatcher = new Dispatcher;
	$dispatcher->setEventsManager($eventsManager);
	return $dispatcher;
});
*/

The code here is shown between comments. As soon as you remove the comments, the Access Control List will start to work so if you have not added access to a range of resources you require for a given user your application will stop working. Plan on commenting out this code to effectively switch off the SecurityPlugin while you call setAccessControl/resource for each resource in your application to get your get your Access Control List set up properly.