5

phalcon_acl.jpg

使用如下图解释这个组件:

phalcon_acl_adapter_database.jpg

实际最终真正要使用的是access_list(ACL),但是这个ACL的填充的场景一般是在后台,先添加具体的role,然后添加resource以及resource_list(一般resource以及resource_list是固定的,因为这两个东西一般对应控制器和控制器的动作),再然后针对role设置access_list,每条access_list组成有roles_name、resources_name、access_name、allowed,检查某个用户(属于某个role)是否可以执行某控制器和动作,就检查对应的控制器和动作在列表中它的allowed的值。如果access_list已经设置好了,在检查用户权限这个步骤,完全可以只使用access_list。PhalconAclAdapter抽象类要求所有的适配器都要提供添加角色,添加资源,添加访问列表,判断权限等功能。

对于角色继承,比如有角色A和B,B继承A,如果要获取A的ACL,只要去access_list查询roles_name为A的记录即可,如果是B,则要查询roles_name为A和B的记录。

从逻辑上看,role,roles_inherits, resource, resource_access应不是ACL对象的组成部分,但是由于要管理这些资源,所有提供了对应方法。

//acl object
$acl = new \Phalcon\Acl\Adapter\Memory();
$acl->setDefaultAction(\Phalcon\Acl::DENY);
 
//role name description
$roleAdmins = new \Phalcon\Acl\Role("Admin","Super-User role");        
$roleGuests = new \Phalcon\Acl\Role("Guests");
$acl->addRole($roleGuests);
 
//roles_inhelit roles_name roles_inherit
$acl->addRole($roleAdmins, $roleGuests);
 
//resource name description
//resource_accesses resources_name access_name
$customersResource = new \Phalcon\Acl\Resource("Customers");
$acl->addResource($customersResource,array("search","edit"));
 
//access_list roles_name resources_name access_name
$acl->allow("Admin","Customers","search");
 
//check acl
//echo $acl->isAllowed("Admin","Customers","edit");
echo $acl->isAllowed("Admin","Customers","update");
    

一般至少要在执行路由前要判断用户是否具有权限(一般在beforeDispatch中),所以ACL应该在它之前获得填充。以下代码可参考:

public function beforeDispatch(Event $event, Dispatcher $dispatcher) {
 
    $auth = $this->session->get('auth');
    if (!$auth){
        $role = 'Guests';
    } else {
        $role = 'Users';
    }
 
    $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();
 
    $acl = $this->getAcl();
 
    $allowed = $acl->isAllowed($role, $controller, $action);
    if ($allowed != Acl::ALLOW) {
        $this->flash->error("You don't have access to this module");
        $dispatcher->forward(
            array(
                'controller' => 'index',
                'action' => 'index'
            )
        );
        return false;
    }
}

这里的getAcl()方法就是重点。参考:

public function getAcl() {
    if (!isset($this->persistent->acl)) {
  
        $acl = new Phalcon\Acl\Adapter\Memory();
 
        $acl->setDefaultAction(Phalcon\Acl::DENY);
 
        //Register roles
        $roles = array(
            'users'  => new Phalcon\Acl\Role('Users'),
            'guests' => new Phalcon\Acl\Role('Guests')
        );
        foreach ($roles as $role) {
             $acl->addRole($role);
        }
 
        //Private area resources
        $privateResources = array(
            'companies'    => array('index', 'search', 'new', 'edit', 'save', 'create', 'delete'),
            'products'     => array('index', 'search', 'new', 'edit', 'save', 'create', 'delete'),
            'producttypes' => array('index', 'search', 'new', 'edit', 'save', 'create', 'delete'),
            'invoices'     => array('index', 'profile')
    );
        foreach ($privateResources as $resource => $actions) {
            $acl->addResource(new Phalcon\Acl\Resource($resource), $actions);
        }
 
        //Public area resources
        $publicResources = array(
            'index'   => array('index'),
            'about'   => array('index'),
            'session' => array('index', 'register', 'start', 'end'),
            'contact' => array('index', 'send')
        );
        foreach ($publicResources as $resource => $actions) {
            $acl->addResource(new Phalcon\Acl\Resource($resource), $actions);
        }
 
        //Grant access to public areas to both users and guests
        foreach ($roles as $role) {
            foreach ($publicResources as $resource => $actions) {
                $acl->allow($role->getName(), $resource, '*');
            }
        }
 
        //Grant acess to private area to role Users
        foreach ($privateResources as $resource => $actions) {
            foreach ($actions as $action){
                $acl->allow('Users', $resource, $action);
            }
        }
 
        //The acl is stored in session, APC would be useful here too
        $this->persistent->acl = $acl;
    }
 
    return $this->persistent->acl;
}

这里把acl对象保存在persistent中。

alc_process.jpg

所有角色 资源 访问列表这些应该是要可配置并且是要保存起来的。但是Phalcon当前只提供PhalconAclAdapterMemory适配器,在它实例化后你需要手动填充它,资源访问列表可以来自数据库等,然后可以把这个对象缓存起来,https://github.com/phalcon/in...中提供了一个保存到数据库的适配器,它可以根据数据表自动填充,可以调用相关方法添加资源、角色、访问列表,而这些如果使用PhalconAclAdapterMemory,那么就要自己去实现。


ZendSNS社区
209 声望8 粉丝