Improve ACL handling.
This commit is contained in:
parent
bcd50a8453
commit
80a8cdca3f
2 changed files with 87 additions and 47 deletions
|
|
@ -2,50 +2,93 @@
|
||||||
|
|
||||||
namespace Httpcb;
|
namespace Httpcb;
|
||||||
|
|
||||||
use Phalcon\Acl\Role,
|
use Phalcon\Config,
|
||||||
Phalcon\Acl\Adapter\Memory as AclList;
|
Phalcon\Acl\Role,
|
||||||
|
Phalcon\Acl\Adapter\Memory as Adapter;
|
||||||
|
|
||||||
class Acl extends AclList
|
class Acl
|
||||||
{
|
{
|
||||||
const ROLE_USER = 'user';
|
const ROLE_USER = 'user';
|
||||||
const ROLE_GUEST = 'guest';
|
const ROLE_GUEST = 'guest';
|
||||||
|
|
||||||
public function __construct()
|
/**
|
||||||
|
* @var Adapter
|
||||||
|
*/
|
||||||
|
protected $_adapter = null;
|
||||||
|
|
||||||
|
public function __construct(Config $config)
|
||||||
{
|
{
|
||||||
|
$this->_adapter = new Adapter();
|
||||||
|
|
||||||
// Deny access to everything by default.
|
// Deny access to everything by default.
|
||||||
$this->setDefaultAction(\Phalcon\Acl::DENY);
|
$this->_adapter->setDefaultAction(\Phalcon\Acl::DENY);
|
||||||
|
|
||||||
// Roles
|
$this->fromConfig($config);
|
||||||
$guest = new Role(self::ROLE_GUEST);
|
|
||||||
$user = new Role(self::ROLE_USER);
|
|
||||||
|
|
||||||
$this->addRole($guest);
|
|
||||||
$this->addRole($user, $guest);
|
|
||||||
|
|
||||||
// Public Resources
|
|
||||||
$public = array(
|
|
||||||
'index',
|
|
||||||
'error',
|
|
||||||
'auth',
|
|
||||||
'api',
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_grant($guest, $public);
|
|
||||||
|
|
||||||
// Protected Resources
|
|
||||||
$protected = array(
|
|
||||||
'callback',
|
|
||||||
'user',
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_grant($user, $protected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _grant(Role $role, array $resources)
|
/**
|
||||||
|
* @param $role
|
||||||
|
* @param $resource
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAllowed($role, $resource)
|
||||||
{
|
{
|
||||||
foreach($resources as $resource) {
|
return $this->_adapter->isAllowed($role, $resource, 'All') == \Phalcon\Acl::ALLOW;
|
||||||
$this->addResource($resource, 'Read');
|
}
|
||||||
$this->allow($role->getName(), $resource, 'Read');
|
|
||||||
|
/**
|
||||||
|
* @param string $resource
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasResource($resource)
|
||||||
|
{
|
||||||
|
return $this->_adapter->isResource($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromConfig(Config $config)
|
||||||
|
{
|
||||||
|
// Add roles.
|
||||||
|
foreach($config->roles as $name => $def) {
|
||||||
|
|
||||||
|
$inherits = null;
|
||||||
|
$description = null;
|
||||||
|
|
||||||
|
if ($def instanceof Config) {
|
||||||
|
$inherits = $def->get('inherits');
|
||||||
|
$description = $def->get('description');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$role = new Role($name, $description);
|
||||||
|
$this->_adapter->addRole($role, $inherits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zones
|
||||||
|
foreach($config->zones as $name => $resources) {
|
||||||
|
|
||||||
|
if (!($resources instanceof Config)) {
|
||||||
|
$resources = new Config([ $resources ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($resources as $resource) {
|
||||||
|
$this->_adapter->addResource($resource, 'All');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grant access for roles and resources.
|
||||||
|
foreach($config->roles as $name => $def) {
|
||||||
|
|
||||||
|
$zones = $def->get('allowed-zones', []);
|
||||||
|
|
||||||
|
if (is_string($zones)) {
|
||||||
|
$zones = [ $zones ];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($zones as $zone) {
|
||||||
|
foreach($config->zones->get($zone) as $resource) {
|
||||||
|
$this->_adapter->allow($name, $resource, 'All');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ use Httpcb\Acl;
|
||||||
|
|
||||||
class AclListener extends Plugin
|
class AclListener extends Plugin
|
||||||
{
|
{
|
||||||
|
protected $_ignored_resources = [
|
||||||
|
'index',
|
||||||
|
'error'
|
||||||
|
];
|
||||||
|
|
||||||
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher) : bool
|
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher) : bool
|
||||||
{
|
{
|
||||||
// We only have two roles for now, authenticated users and guests.
|
// We only have two roles for now, authenticated users and guests.
|
||||||
|
|
@ -19,24 +24,17 @@ class AclListener extends Plugin
|
||||||
$role = Acl::ROLE_GUEST;
|
$role = Acl::ROLE_GUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support annotations for actions to define custom resources.
|
// Get the resource from controller name.
|
||||||
$controllerClass = $dispatcher->getControllerClass();
|
$resource = $dispatcher->getControllerName();
|
||||||
$activeMethod = $dispatcher->getActiveMethod();
|
|
||||||
|
|
||||||
$annotation = $this->annotations->getMethod($controllerClass, $activeMethod);
|
// Ignore checks for error resource.
|
||||||
|
if (in_array($resource, $this->_ignored_resources)) {
|
||||||
// ACL annotation found. use that.
|
return true;
|
||||||
if ($annotation->has('Acl')) {
|
|
||||||
$resource = $annotation->get('Acl')->getArgument('resource');
|
|
||||||
}
|
|
||||||
// Otherwise, default to controller name.
|
|
||||||
else {
|
|
||||||
$resource = $dispatcher->getControllerName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, check and redirect user to login page if
|
// Now, check and redirect user to login page if
|
||||||
// this role does not have access to this resource.
|
// this role does not have access to this resource.
|
||||||
if ($this->acl->isAllowed($role, $resource, 'Read') == \Phalcon\Acl::DENY) {
|
if ($this->acl->isAllowed($role, $resource) === false) {
|
||||||
|
|
||||||
// Forward to login page.
|
// Forward to login page.
|
||||||
$dispatcher->forward(array(
|
$dispatcher->forward(array(
|
||||||
|
|
@ -47,7 +45,6 @@ class AclListener extends Plugin
|
||||||
// Return false to stop the dispatch loop.
|
// Return false to stop the dispatch loop.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue