Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 29-10-2007 11:23:58

vallica
Membre
Date d'inscription: 25-10-2007
Messages: 34

Architecture modulaire et ACL

Bonjour à tous,

Je débute totalement sous ZF, mais j'ai déjà pas mal bossé sur des frameworks J2EE, donc ca va j'avance assez vite mais j'ai besoin de vos conseils pour mon architecture en modules et la gestion des droits.

Voici le contexte :

Dans mon appli j'aurais plusieurs niveau d'utilisateurs, j'ai donc les modules suivants :

Default (dans lequel je met le controleur de l'authentification, celui des erreurs, etc.)
Niveau1 (contient les controlleurs et actions de niveau1)
Niveau2 (contient les controlleurs et actions de niveau2)
...

La capture d'écran ci-dessous vous montre mon architecture physique de fichiers que j'ai constituée petit à petit en suivant les différents tutos disponibles sur le net.
http://images2.hiboox.com/images/4407/61de2a7d.jpg

A ce stade j'ai implémenté l'authentification via Zend_Auth et une base MySQL, et maintenant je voudrais utiliser les ACL pour définir les droits de chaque utilisateur.

J'ai essayé de mettre en oeuvre les tutos sur les ACL mais j'ai une question :

D'après ce que j'ai compris, dans les tutos on déclare des ressources, que l'on pourrait nommer comme on veut, exemple je déclare la ressource "toto", je dit que "guest" peut y accéder et ensuite c'est à moi de voir dans mes controlleurs si la personne qui demande l'action est bien "guest" et si il a le droit "toto".

Hors ce que j'aurais aimé, c'est définir des droits en fonction du nom de mes modules/controlleurs/actions.

C'est à dire pouvoir dire que le rôle "guest" permet d'accéder à HOST/niveau1/caisseauto/afficher, et que le rôle "gestionnaire1" permet d'accéder à HOST/niveau1/caisseauto/saisir.

Le tout sans rien rajouter dans mes différents contrôleurs...

J'espère avoir été assez clair et merci d'avance pour vos conseils.

Dernière modification par vallica (29-10-2007 11:25:20)

Hors ligne

 

#2 29-10-2007 13:23:59

philippe
Administrateur
Lieu: Grenoble
Date d'inscription: 01-03-2007
Messages: 1624

Re: Architecture modulaire et ACL

Bonjour,

Tu as un exemple un peu plus complet dans le tuto suivant : http://devzone.zend.com/node/view/id/1665 .
Dans ce tutoriel, les tests de droits se font dans un plugin (en fonction du controller de de l'action appelée. Tu peux l'adapter pour ajouter les modules) et non dans les actions.

A+, Philippe


twitter : @plv ; kitpages.fr : Création de sites internet à Grenoble et Paris

Hors ligne

 

#3 29-10-2007 14:10:29

Mr.MoOx
Administrateur
Lieu: Toulouse
Date d'inscription: 27-03-2007
Messages: 1444
Site web

Re: Architecture modulaire et ACL

Dans ce tuto, pensez à regarder dans les commentaires les parties manquantes du code présent dans le tuto afin qu'il fonctionne correctement!

Hors ligne

 

#4 29-10-2007 14:18:03

vallica
Membre
Date d'inscription: 25-10-2007
Messages: 34

Re: Architecture modulaire et ACL

OK merci à tous les deux, je commence la lecture

Hors ligne

 

#5 29-10-2007 15:16:25

vallica
Membre
Date d'inscription: 25-10-2007
Messages: 34

Re: Architecture modulaire et ACL

C'est encore moi, j'ai un souci avec le code du tuto qui semble "perimé" d'après les commentaires.

J'obtiens l'erreur

Code:

Fatal error: Can not call constructor in F:\www\zend\index.php on line 36

lorsque j'utilise ce bootstrap :

Code:

<?php
error_reporting(E_ALL|E_STRICT);

date_default_timezone_set('Europe/Paris');

include "Zend/Loader.php";
Zend_Loader::loadClass('Zend_Controller_Front');
Zend_Loader::loadClass('Zend_Config_Ini');
Zend_Loader::loadClass('Zend_Registry');
Zend_Loader::loadClass('Zend_Db');
Zend_Loader::loadClass('Zend_Db_Table');
// auth
Zend_Loader::loadClass("Zend_Auth");
Zend_Loader::loadClass("Zend_Auth_Result");
Zend_Loader::loadClass("Zend_Auth_Adapter_Interface");
Zend_Loader::loadClass("Zend_Acl");

// Chargement du fichier ini de config
$config = new Zend_Config_Ini('./application/config.ini', 'general');
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);

// setup database
$db = Zend_Db::factory($config->db->adapter,  $config->db->config->toArray());
Zend_Db_Table::setDefaultAdapter($db);
Zend_Registry::set('dbAdapter', $db);

// Create auth object
$auth = Zend_Auth::getInstance();

// Create acl object
class MyAcl extends Zend_Acl
{
    public function __construct(Zend_Auth $auth)
    {
        parent::__construct();

        $this->add(new Zend_Acl_Resource('niveau1'));
        $this->add(new Zend_Acl_Resource('niveau2'));

        // le rôle superviseur aura accès au module nommé Niveau1
        $this->addRole(new Zend_Acl_Role('superviseur'));
        $this->allow('superviseur', 'niveau1');
         
        // le rôle coordinateur aura accès au module nommé Niveau2
        $this->addRole(new Zend_Acl_Role('coordinateur')); 
        $this->allow('coordinateur', 'niveau2');
        
        // le rôle admin donne accès à tout
        $this->addRole(new Zend_Acl_Role('admin')); 
        $this->allow('admin');
    }
}
$acl = new MyAcl($auth);



// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);

$frontController->setControllerDirectory(array(
        'default' => 'application/modules/default/controllers',
        'niveau1' => 'application/modules/Niveau1/controllers'    
));

//$frontController->addModuleDirectory('application/modules');

// run!
$frontController->dispatch();

La ligne en question c'est

Code:

$acl = new MyAcl($auth);

, et un commentaire nous dit

Howdy folks,

Just wanted to post to let everyone know that calling parent::__construct() on a class that extends Zend_Acl will result in fatal error because Zend_Acl does not have a constructor.

So, for those of you following this old article verbatim, beware that much has changed for both Zend_Auth and Zend_Acl since this writing.

Best regards,
Darby

En gros je crois comprendre que la conception des classes Auth et Acl a été fortement modifiée ce qui l'article obsolète...

Auriez-vous une idée de ce qui a changé ? je suis désolé d'être aussi insistant mais la documentation ne m'aide pas beaucoup sur mon approche en modules.

Merci d'avance.

Hors ligne

 

#6 12-11-2007 23:27:08

neni
Membre
Lieu: Nantes
Date d'inscription: 12-11-2007
Messages: 27

Re: Architecture modulaire et ACL

Effectivement, le code à utiliser est un peu différent.

Voici des fichiers modifiés (basé sur l'exemple de devzone.zend.com) qui fonctionnent sur un de mes projet:

index.php:

Code:

<?php


/**
 * 
 *
 * 
 * 
 */

 
// pour le developpement
error_reporting(E_ALL|E_STRICT);


// chemin vers racine du site 
define('SITE_PATH', './'); 

// chemin vers moteur application
define('LIB_PATH', './application/');


// la date 
date_default_timezone_set('Europe/Paris');


// les includes de base
set_include_path(
      LIB_PATH
    . PATH_SEPARATOR . LIB_PATH . 'lib/ZF'
    . PATH_SEPARATOR . LIB_PATH . 'lib/ZF/library'
    //. PATH_SEPARATOR . LIB_PATH . 'lib/ZF/incubator/library'
    . PATH_SEPARATOR . LIB_PATH . 'lib/Neni'
    . PATH_SEPARATOR . LIB_PATH . 'models'
    . PATH_SEPARATOR . get_include_path()
);


// A METTRE AILLEURS : FONCTIONS POUR CONVERTIR
function ConvertJSDateToMysql($txt){
    $tmp = explode('/',$txt);
    if( (isset($tmp[2]))&&(isset($tmp[1]))&&(isset($tmp[0])) ){
        return $tmp[2].'-'.$tmp[1].'-'.$tmp[0];
    }else{
        return 'NULL';
    }
}


// init
require_once 'Zend/Loader.php';
require_once 'Zend/Registry.php';

// le fichier de configuration
require_once 'Zend/Config/Ini.php';
$config = new Zend_Config(new Zend_Config_Ini('./application/config/config.ini', 'test'));


// adresse absolue du site 
define('SITE_URL', $config->weburl); 
define('SITE_ABS_URL', 'http://'.$config->webhost.$config->weburl); 


// la BDD
require_once 'Zend/Db.php';
require_once 'Zend/Db/Adapter/Pdo/Mysql.php';
$db = Zend_Db::factory($config->database);
Zend_Registry::set('db', $db);

// identification
require_once 'Zend/Auth.php';
$auth = Zend_Auth::getInstance();
require_once 'Zend/Auth/Storage/Session.php';
$auth->setStorage(new Zend_Auth_Storage_Session('leNomQuiVaBien'));
Zend_Registry::set('auth', $auth);

// les droits de l'application
require_once("ModemAcl.php");
$acl = new Modem_Acl($auth);
Zend_Registry::set('acl', $acl);


// on y va
require_once 'Zend/Controller/Front.php';
require_once 'Zend/Controller/Router/Rewrite.php';
require_once 'Neni_PluginAuth.php';
$router = new Zend_Controller_Router_Rewrite;
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory(LIB_PATH.'bureau/controllers');
$front->throwExceptions(true);
$front->addModuleDirectory(LIB_PATH.'modules');
$front->setRouter($router)
      ->setDispatcher(new Zend_Controller_Dispatcher_Standard())
      ->setRouter(new Zend_Controller_Router_Rewrite())
      ->registerPlugin(new Neni_PluginAuth($auth, $acl));
$front->dispatch();


?>

Le plugin de test de l'utilisateur et des droits (en un seul à la différence de l'original):

Code:

<?php

// verification que session ok
// et aussi que droit ok


require_once 'Zend/Controller/Plugin/Abstract.php';

class Neni_PluginAuth extends Zend_Controller_Plugin_Abstract
{
    private $_auth;
    private $_acl;

    private $_login = array('module' => 'default',
                             'controller' => 'index',
                             'action' => 'index');

    private $_noauth = array('module' => 'default',
                             'controller' => 'login',
                             'action' => 'session');

    private $_noagreement = array('module' => 'default',
                            'controller' => 'login',
                            'action' => 'privileges');

   
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {

        $this->_auth = Zend_Registry::get('auth');
        $this->_acl = Zend_Registry::get('acl');

        if ($this->_auth->hasIdentity()) {
            $role = $this->_auth->getStorage()->read()->role;
        } else {
            $role = 'invite';
        }
       
        $controller = $request->controller;
        $action = $request->action;
        $module = $request->module;
        $resource = $controller;
   
            
        if (!$this->_acl->has($resource)) {
            $resource = null;
        }

            // test session
            if (!$this->_auth->hasIdentity()) {
                // test si la première page
                if(($controller=='index')&&($module=='default')){
                    $module = $this->_login['module'];
                    $controller = $this->_login['controller'];
                    $action = $this->_login['action'];
                // si le login
                }else if(($controller!='login')&&($module!='default')){
                    $module = $this->_noauth['module'];
                    $controller = $this->_noauth['controller'];
                    $action = $this->_noauth['action'];
                }
            }else{
                // test droits

            //$f = fopen('debug.txt','a');
            //fwrite($f,"module:".    $module."\ncontroller:".$controller."\naction:".    $action."\n");
            //fwrite($f,'role:'.$role."\nautrisaition:".(($this->_acl->isAllowed($role, $module, /*$controller,*/ $action))?'oui':'non')."\n\n");
            //fclose($f);
            
                if(!$this->_acl->isAllowed($role, $module, /*$controller,*/ $action)){
                    $module = $this->_noagreement['module'];
                    $controller = $this->_noagreement['controller'];
                    $action = $this->_noagreement['action'];
                }
            }

        $request->setModuleName($module);
        $request->setControllerName($controller);
        $request->setActionName($action);
    }
    
    
}

et enfin le contrôleur pour le login:

Code:

<?php


//
// Login sur bureau
//

require_once 'Zend/Controller/Action.php';



class LoginController extends Zend_Controller_Action 
{

    var $db, $auth;

    public function init()
    {
        Zend_Controller_Front::getInstance()->setParam('noViewRenderer', true);
        $this->db = Zend_Registry::get('db');
        $this->auth  = Zend_Registry::get('auth');
        //$this->getResponse()->setHeader('Content-Type', 'application/x-json');
    }



    public function indexAction() 
    {
        // verification pas vide
        if((!isset($_POST['login']))||(!isset($_POST['password']))||($_POST['login']=='')||($_POST['password']==''))
        {
            $data['success'] = false;
        }
        else
        {
            // regarde si dans la BDD
            require_once 'Zend/Auth/Adapter/DbTable.php';
            $authAdapter = new Zend_Auth_Adapter_DbTable($this->db);
            $authAdapter->setTableName('bureau_utilisateur')
                ->setIdentityColumn('pseudo')
                ->setCredentialColumn('password');

            $authAdapter->setIdentity($_POST['login'])
                ->setCredential($_POST['password']);
                

           $result = $this->auth->authenticate($authAdapter);
            if ($result->isValid()) 
            {
                $data['success'] = true;
                // sauvegarde dans session
                $this->auth->getStorage()->write($authAdapter->getResultRowObject(array('id', 'pseudo', 'nom', 'prenom', 'email', 'role','actif')));
                // on envoie le bureau à afficher
                $data['data']=$this->auth->getStorage()->read();
            }
            else
            {
                $data['success'] = false;
            }

        }

        $this->getResponse()->setBody(json_encode($data));

    }


    // si plus d'identité (delai session) 
    public function sessionAction() 
    {
        $this->getResponse()->setBody('{success:false,initialisation:pbreconnect(),message:"session"}');
    }

    // si pas les privileges 
    public function privilegesAction() 
    {
        $this->getResponse()->setBody('{success:false,initialisation:pbpasdedroits(),message:"droit"}');
    }

    

}

Dans cet exemple, c'est du Json qui sort, mais il n'est pas bien compliqué de faire autre chose.


Vous pouvez trouver les sources de l'application (début d'un bureau en ligne pour la gestion d'une association) ici:
http://www.neni.org/Site_test.tar.bz2
Si vous voulez le tester, il suffit de modifier le fichier /application/config/config.ini (info sur bdd) et de faire la table utilisateur avec le fichier SQL dans /apllication/sql.

Dernière modification par neni (12-11-2007 23:34:32)

Hors ligne

 

#7 13-11-2007 07:25:38

vallica
Membre
Date d'inscription: 25-10-2007
Messages: 34

Re: Architecture modulaire et ACL

Merci, entre temps j'avais réussi à faire tourner le code mais je vais essayer le tiens prochainement pour peut-être m'en inspirer.

Bon dev wink

Hors ligne

 

#8 28-01-2008 22:31:20

astec37
Nouveau membre
Lieu: Angers
Date d'inscription: 05-10-2007
Messages: 8

Re: Architecture modulaire et ACL

Bonjour à tous

Désolé de faire remonter ce post, mais j'ai quelques soucis en essayant moi aussi d'adapter mon code à "l'ancien" de Devzone.zend.

J'ai donc fais ma classe MyAcl définissant les ressources et les rôles. J'ai pu tester que cela fonctionnait. Je souhaite maintenant mettre en place le plugin permettant de tester la permission d'afficher ce qui à été demndé en fonction du rôle de l'utilisateur. Et c'est là que ça coince...
Voici un peu de code.

Tout d'abord, le bootstrap :

Code:

// Create auth object
$auth = Zend_Auth::getInstance();
// Create acl object
$acl = new MyAcl($auth); // see 

....

// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->registerPlugin(new MyPluginAuth($auth, $acl));
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('./application/controllers');

// run!
$frontController->dispatch();

Ensuite le plugin (il s'agit du même que pour le tuto)

Code:

<?php

class MyPluginAuth extends Zend_Controller_Plugin_Abstract
{
    private $_auth;
    private $_acl;

    private $_noauth = array('module' => 'default',
        'controller' => 'login',
        'action' => 'index');

    private $_noacl = array('module' => 'default',
        'controller' => 'error',
        'action' => 'privileges');

    public function __construct($auth, $acl)
    {
        $this->_auth = $auth;
        $this->_acl = $acl;
    }

    public function preDispatch($request)
    {
    
            if ($this->_auth->hasIdentity()) {
                // Recuperer içi le role de l'utilisateur connecté
                //$role = $this->_auth->getIdentity()->getUser()->role;
                $role = 'membre';
            } else {
                $role = 'invite';
            }
        
        
            
        $role = 'invite';
        
        
        $controller = $request->controller;
        $action = $request->action;
        $module = $request->module;
        $resource = $controller;

        if (!$this->_acl->has($resource)) {
            $resource = null;
        }

        if (!$this->_acl->isAllowed($role, $resource, $action)) {
            if (!$this->_auth->hasIdentity()) {
                $module = $this->_noauth['module'];
                $controller = $this->_noauth['controller'];
                $action = $this->_noauth['action'];
            } else {
                $module = $this->_noacl['module'];
                $controller = $this->_noacl['controller'];
                $action = $this->_noacl['action'];
            }
        }

        $request->setModuleName($module);
        $request->setControllerName($controller);
        $request->setActionName($action);

    }
}

Et le problème c'est que tout ça me retourne deux grosses erreurs :

Code:

Strict Standards: Declaration of MyPluginAuth::preDispatch() should be compatible with that of Zend_Controller_Plugin_Abstract::preDispatch() in /Applications/MAMP/htdocs/SncfStore/application/lib/MyPluginAuth.php on line 63

Fatal error: Uncaught exception 'Zend_Session_Exception' with message 'Session must be started before any output has been sent to the browser; output started in /Applications/MAMP/htdocs/SncfStore/application/lib/MyPluginAuth.php/63' in /Applications/MAMP/htdocs/library/Zend/Session.php:359 Stack trace: #0 /Applications/MAMP/htdocs/library/Zend/Session/Namespace.php(116): Zend_Session::start(true) #1 /Applications/MAMP/htdocs/library/Zend/Auth/Storage/Session.php(85): Zend_Session_Namespace->__construct('sessionauth') #2 /Applications/MAMP/htdocs/SncfStore/index.php(60): Zend_Auth_Storage_Session->__construct('sessionauth') #3 {main} thrown in /Applications/MAMP/htdocs/library/Zend/Session.php on line 359

J'ai bien cherché mais je ne vois pas comment y remedier...  Si vous avez des idées, je suis novice, donc preneur !

Merci d'avance

Guiton

Hors ligne

 

#9 28-01-2008 22:51:54

julz
Membre
Date d'inscription: 19-07-2007
Messages: 33

Re: Architecture modulaire et ACL

hello,

il faut utiliser la même déclaration que dans Zend_Controller_Plugin_Abstract , y compris le typage de $request

Code:

public function preDispatch(Zend_Controller_Request_Abstract $request)

et là ca marchera sans problème

bonne soirée

Hors ligne

 

#10 29-01-2008 10:12:27

astec37
Nouveau membre
Lieu: Angers
Date d'inscription: 05-10-2007
Messages: 8

Re: Architecture modulaire et ACL

Salut,
Merci de cette réponse julz, j'ai un peu honte d'être passé à côté de ça quand même...
Mais bon, ça fonctionne parfaitement, alors merci !

Bonne journée

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages