views:

4201

answers:

2
+2  Q: 

Help with Zend ACL

hello,

I am currently working on a site that requires use of ACL and seen as I am using Zend it makes sense for my make use of there ACL class but I have little to zero idea of how to do this, I have read the docs but this has confused me further...basically all I want do is set up two user groups e.g. normal and admin, normal users can access all pages that have a controller that is not admin while admin can obvioulsy access the admin controller pages.

I have many questions, one how do I set this up? Is run through a DB or the config.ini, where do I place my ACL.php how do I write such a script? How do i then call, is this done in the Index?

If some good guide me or lead to a turorial or website I would be very appreciative.

+9  A: 

I implemented similar thing not so long ago. Basic concept follows in an example code.

I created my own configAcl.php file which is loaded in bootstrap file, in my case it is index.php. Here is how it'd be according to your case:

$acl = new Zend_Acl();

$roles  = array('admin', 'normal');

// Controller script names. You have to add all of them if credential check
// is global to your application.
$controllers = array('auth', 'index', 'news', 'admin');

foreach ($roles as $role) {
    $acl->addRole(new Zend_Acl_Role($role));
}
foreach ($controllers as $controller) {
    $acl->add(new Zend_Acl_Resource($controller));
}

// Here comes credential definiton for admin user.
$acl->allow('admin'); // Has access to everything.

// Here comes credential definition for normal user.
$acl->allow('normal'); // Has access to everything...
$acl->deny('normal', 'admin'); // ... except the admin controller.

// Finally I store whole ACL definition to registry for use
// in AuthPlugin plugin.
$registry = Zend_Registry::getInstance();
$registry->set('acl', $acl);

Another case is if you want to allow normal user only "list" action on all your controllers. It's pretty simple, you'd add line like this:

$acl->allow('normal', null, 'list'); // Has access to all controller list actions.

Next you should create new plugin which takes care of credential checking automatically when there is a request for some controller action. This checking takes place in preDispatch() method that is called before every call to the controller action.

Here is AuthPlugin.php:

class AuthPlugin extends Zend_Controller_Plugin_Abstract
{
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        $loginController = 'auth';
        $loginAction     = 'login';

        $auth = Zend_Auth::getInstance();

        // If user is not logged in and is not requesting login page
        // - redirect to login page.
        if (!$auth->hasIdentity()
                && $request->getControllerName() != $loginController
                && $request->getActionName()     != $loginAction) {

            $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector');
            $redirector->gotoSimpleAndExit($loginAction, $loginController);
        }

        // User is logged in or on login page.

        if ($auth->hasIdentity()) {
            // Is logged in
            // Let's check the credential
            $registry = Zend_Registry::getInstance();
            $acl = $registry->get('acl');
            $identity = $auth->getIdentity();
            // role is a column in the user table (database)
            $isAllowed = $acl->isAllowed($identity->role,
                                         $request->getControllerName(),
                                         $request->getActionName());
            if (!$isAllowed) {
                $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector');
                $redirector->gotoUrlAndExit('/');
            }
        }
    }
}

Final steps are loading your configAcl.php and register the AuthPlugin in bootstrap file (probably index.php).

require_once '../application/configAcl.php';

$frontController = Zend_Controller_Front::getInstance();
$frontController->registerPlugin(new AuthPlugin());

So this is the basic concept. I didn't test the code above (copy and paste and rewrite just for the showcase purpose) so it's not bullet-proof. Just to give an idea.

EDIT

For the clarity. The code above in AuthPlugin suppose that the $identity object is filled with user data ("role" column in the database). This could be done within the login process like this:

[...]
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
$authAdapter->setTableName('Users');
$authAdapter->setIdentityColumn('username');
$authAdapter->setCredentialColumn('password');
$authAdapter->setIdentity($username);
$authAdapter->setCredential(sha1($password));
$authAdapter->setCredentialTreatment('? AND active = 1');
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
    $data = $authAdapter->getResultRowObject(null, 'password'); // without password
    $auth->getStorage()->write($data);
[...]
Marek Janouch
Where does this go in my site structure?APPLICATIONcontrollermodelsviewsPUBLICcssimagesjsflashLIBRARYzendany advice?
sico87
configAcl.php can be anywhere in your Application directory, it's only for inclusion in index.php. AuthPlugin should be in your Library - thus Zend is able to autoload it and you don't have to use require_once. The last statements between [...] depend on your login process...
Marek Janouch
+6  A: 

I wrote an article on my blog about Zend_Acl...bottom line is that Zend_Acl should be working with your models. Your User models should implement Zend_Acl_Rolde_Interface and your other models should implement Zend_Acl_Resource_Interface. When you try to act on these models, you pass your user object and model object in to $acl->isAllowed(). An added plus here, is that if you need a custom assertion (like only an article author can edit his own article), you get your exact models passed into the assertion, and you don't need to mess around with the request object or with Zend_Auth.

For simply protecting pages, I would stay away from using "controllers" as resources and "actions" as permissions, as this ties your application to your URL structure. Instead I would look into Zend_Navigation. I believe Zend_Navigation even comes with a streamlined way of adding in Zend_Acl setups.

For more info check our my article http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/

blockhead