Listas de control de acceso ACL en Zend Framework 2

En Zend Framewok 2 al igual que en otros frameworks, tenemos una funcionalidad muy interesante, las listas de control de acceso. Con ellas podemos definir una serie de roles para los usuarios y darles o quitarles permiso de acceso a ciertas partes de la aplicación.

Ejemplo de implementación de ACL en Zend Framework 2:

En nuestro module.config.php tenemos definidas estas rutas:
listas de control de acceso acl en Zend Framework 2

A mi parecer la mejor forma de implementar esto, es creando el fichero acl.roles.php en el directorio config/autoload de la aplicación en general.
Aquí devolvemos un array con los diferentes roles y rutas de la aplicación permitidas, de esta forma:

<?php
return array(
    'visitante'=> array(
        "allow"=>array(
               'usuarios'
        ),
        "deny"=>array(
               'crud'
        )
    ),
    'admin'=> array(
        "allow"=>array(
            'crud',
            'usuarios'
        ),
        "deny"=>array(
 
        )
    ),
);
?>

Al visitante solo le permitimos que entre en la ruta usuarios y al admin le permitimos que entre a todas las rutas sin denegarle el acceso a ninguna ruta.

En el fichero Module.php de nuestro modulo tenemos que tener una configuración similar a la siguiente.

<?php
namespace Modulo;

use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;

class Module{

    public function getConfig(){
        return include __DIR__ . '/config/module.config.php';
    }

    public function getAutoloaderConfig(){
        return array(
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }

//Este método se ejecuta cada vez que carga una página
    public function onBootstrap(MvcEvent $e){
        //Iniciamos la lista de control de acceso
        $this->initAcl($e);
        
        //Comprobamos la lista de control de acceso
        $e->getApplication()->getEventManager()->attach('route', array($this, 'checkAcl'));
    }
 
    public function initAcl(MvcEvent $e){
        //Creamos el objeto ACL
        $acl = new \Zend\Permissions\Acl\Acl();
        
        //Incluimos la lista de roles y permisos, nos devuelve un array
        $roles=require_once 'config/autoload/acl.roles.php';
        
        foreach($roles as $role => $resources){
          
            //Indicamos que el rol será genérico
            $role = new \Zend\Permissions\Acl\Role\GenericRole($role);
            
            //Añadimos el rol al ACL
            $acl->addRole($role);
            
            //Recorremos los recursos o rutas permitidas
            foreach($resources["allow"] as $resource){
            
                //Si el recurso no existe lo añadimos
                 if(!$acl->hasResource($resource)){
                    $acl->addResource(new \Zend\Permissions\Acl\Resource\GenericResource($resource));
                 }
                 
                 //Permitimos a ese rol ese recurso
                 $acl->allow($role, $resource);
            }
            
            foreach ($resources["deny"] as $resource) {
                 
                 //Si el recurso no existe lo añadimos
                 if(!$acl->hasResource($resource)){
                    $acl->addResource(new \Zend\Permissions\Acl\Resource\GenericResource($resource));
                 }
                 
                 //Denegamos a ese rol ese recurso
                 $acl->deny($role, $resource);
            }
 
        }
        
        //Establecemos la lista de control de acceso
        $e->getViewModel()->acl=$acl;
    }
 
    public function checkAcl(MvcEvent $e){
        //guardamos el nombre de la ruta o recurso a permitir o denegar
        $route=$e->getRouteMatch()->getMatchedRouteName();
        
        //Instanciamos el servicio de autenticacion
        $auth=new \Zend\Authentication\AuthenticationService();
        $identi=$auth->getStorage()->read();
        
        // Establecemos nuestro rol
        // $userRole = 'admin';
        
        // Si el usuario esta identificado le asignaremos el rol admin y si no el rol visitante.
        if($identi!=false && $identi!=null){
           $userRole="admin";
        }else{
           $userRole="visitante"; 
        }
        /* 
        Esto se puede mejorar fácilmente, si tenemos un campo rol en la BD cuando el usuario
        se identifique en la sesión se guardarán todos los datos del mismo, de modo que 
        $userRole=$identi->role; 
        */
        
        //Comprobamos si no está permitido para ese rol esa ruta
        if(!$e->getViewModel()->acl->isAllowed($userRole, $route)) {
        
        //Devolvemos un error 404
            $response = $e->getResponse();
            $response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseUrl() . '/404');
            $response->setStatusCode(404); 
        }
        
    }
}

Más información:
ACL en Zend Framework 2 en 5 minutos
Autenticación y ACL en Zend Framework 2
ACL en Zend Framework 2 Documentación oficial

Victor

Autor: Victor

Desarrollador web - Formador online - Blogger

Compartir este post

4 Comentarios

  1. Y como puedo ahora imprimir un menu en mi layout solo de las opciones que el usuario actual tiene permiso?

    Responder
    • Simplemente haz una condición, con un if, si el usuario está identificado muéstrame el menú.

      Responder
  2. hola, primero muchas gracias por los aportes.

    podria dar permisos a una accion en especifico?, me explico digamos que tengo un modulo usuarios con acciones crear, modificar y eliminar usuarios, podria decir que un rol solo tiene permiso a modificar ?

    Responder
    • Si puedes, podrías definir rutas para esas acciones y darles permiso o no.

      Responder

Poner un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *