A web developer's blog. PHP, MySQL, CakePHP, Zend Framework, Wordpress, Code Igniter, Django, Python, CSS, Javascript, jQuery, Knockout.js, and other web development topics.

Zend Framework Zend_Auth and a Plugin to Check Access to a Page

I have written this simple user authentication and user access privilege plugin in one of my Web Apps.

First, in my AuthController, I have something like this:

    public function loginAction()
    {
        try {
            if ($this->_request->isPost()) { 
                // collect the data from the user 
                $f = new Zend_Filter_StripTags(); 
                $username = $f->filter($this->_request->getPost('username')); 
                $password = $f->filter($this->_request->getPost('password'));
                $password = md5($password); 
 
                if (empty($username)) { 
                    $this->_flashMessenger->addMessage('Provide a username.');
                    $this->_redirect('auth/');
                } else { 
                    // setup Zend_Auth adapter for a database table 
                    $dbAdapter = Zend_Registry::get('dbAdapter'); 
                    $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter); 
                    $authAdapter->setTableName('users'); 
                    $authAdapter->setIdentityColumn('username'); 
                    $authAdapter->setCredentialColumn('password'); 
 
                    // Set the input credential values to authenticate against 
                    $authAdapter->setIdentity($username); 
                    $authAdapter->setCredential($password); 
 
                    // do the authentication  
                    $auth = Zend_Auth::getInstance(); 
                    $result = $auth->authenticate($authAdapter); 
                    if ($result->isValid()) { 
                        // success: store database row to auth's storage 
                        // system. (Not the password though!) 
                        $data = $authAdapter->getResultRowObject(null, 'password'); 
 
                        $auth->getStorage()->write($data); 
 
                        $user = Zend_Auth::getInstance()->getIdentity();
 
                        $dbAdapter = Zend_Registry::get('dbAdapter');
 
                        $sql = 'SELECT
                            ug.*,
                            g.*
                            FROM user_group ug
                            LEFT JOIN groups g ON ug.group_id = g.id
                            WHERE ug.user_id="'.$user->id.'"';
                        $groups = $dbAdapter->fetchAll($sql);
 
                        $mygroups = array();
                        foreach ($groups AS $group) {
 
                            //query permissions table
                            $sql = '
                                SELECT *
                                FROM permissions
                                WHERE group_id="'.$group['group_id'].'"
                            ';
                            $group_permission = $dbAdapter->fetchAll($sql);
 
                            $mygroups[]['group_name'] = $group['group_name'];
                            $mygroups['group_permission'] = $group_permission;
                        }
 
                        //get the Zend_Auth and then save the roles
                        $authNamespace = new Zend_Session_Namespace('Zend_Auth');
                        $authNamespace->storage->mygroups = $mygroups;
 
                        $this->_flashMessenger->addMessage('Login Successful.');
                        $this->_redirect('/');
                    } else { 
                        $this->_flashMessenger->addMessage('Login Failed. Please enter a valid username/password.');
                        $this->_redirect('/auth/');
                    } 
                }
            }
        } catch (Exception $e){
            echo $e->getMessage();
        }
        $this->view->messages = $this->_flashMessenger->getMessages();
        $this->_helper->viewRenderer->setNoRender(); //suppress auto-rendering

I know I should have done the queries in my User Model instead of inserting them in-line with the loginAction. Anyways, I did that do give you an idea of what I am querying.

Now, for the plugin. In my library folder, beside the Zend folder – which contains all the Zend Framework core files, I have a directory called Ekini.

../library/Ekini/Controller/Plugin/

Inside the Plugin directory, I have this file called: CheckHasAccess.php

The file contains the following code:

< ?php
class Ekini_Controller_Plugin_CheckHasAccess extends Zend_Controller_Plugin_Abstract {
 
    /**
     * Checks if a user is allowed to access the current controller
     * Returns true if allowed
     * redirects to the noaccess.phtml found in auth controller if user is not allowed
     *
     * @param Zend_Controller_Request_Abstract $request
     * @return unknown
     */
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {   
        try {
 
            $moduleName         = $this->getRequest()->getModuleName();
            $controllerName     = $this->getRequest()->getControllerName();
            $actionName         = $this->getRequest()->getActionName();
            $frontController    = Zend_Controller_Front::getInstance();
            $user = Zend_Auth::getInstance()->getIdentity();
 
 
            if($controllerName == 'admin' AND !isset($user)) {
                throw new Exception('You must login to access this page.');
            }
 
            //check $user->mygroups['group_permission'] array
            //echo $moduleName.' '.$controllerName.' '.$actionName;
            //Zend_Debug::dump($user->mygroups['group_permission']);
 
            if (isset($user)) {
                $permissions = $user->mygroups['group_permission'];
 
                //check for module ONLY - controller and action must be NULL
                for($i=0;$i<count ($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == NULL AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this module.');    
                        }
                }
 
                //check for controller+module - action is blank
                for($i=0;$i<count($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this controller.');    
                        }
                }
 
                //check for the module / controller / action - look for deny
                for($i=0;$i<count($permissions);$i++) {
                    //echo $permissions[$i]['module_name'].' '.$permissions[$i]['permission'].'<br>';
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND 
                        $permissions[$i]['action_name'] == $actionName AND 
                        $permissions[$i]['permission'] == 'deny') {
 
                        throw new Exception('You are not allowed to access this page.');
                    }
                }
 
                //if guest session exists, unset it
                Zend_Session::sessionExists('Guest_Session')?Zend_Session::namespaceUnset('Guest_Session'):'';
 
            } elseif(Zend_Session::namespaceIsset('Guest_Session')) {
                //this part executes only when the Guest_Session is set
                //so that we only have to query the database once
                //querying the database is in the else
                //after querying, the Guest_Session is set.
 
                $guest = new Zend_Session_Namespace('Guest_Session');
 
                $permissions = $guest->guestRoles;
                //Zend_Debug::dump($guest);
                //echo 'guest session exists!';
                //check for module ONLY - controller and action must be NULL
                for($i=0;$i</count><count ($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == NULL AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this module.');    
                        }
                }
 
                //check for controller+module - action is blank
                for($i=0;$i<count($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this controller.');    
                        }
                }
 
                //check for the module / controller / action - look for deny
                for($i=0;$i<count($permissions);$i++) {
                    //echo $permissions[$i]['module_name'].' '.$permissions[$i]['permission'].'<br>';
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND 
                        $permissions[$i]['action_name'] == $actionName AND 
                        $permissions[$i]['permission'] == 'deny') {
 
                        throw new Exception('You are not allowed to access this page.');
                    }
                }   
            } else {
                //query the database for permissions and then set Guest_Session
                $guestSession = new Zend_Session_Namespace('Guest_Session');
 
                //Not logged in, so check guest/unregistered user
                //query permissions table
                $dbAdapter = Zend_Registry::get('dbAdapter');
                $sql = '
                    SELECT *
                    FROM permissions
                    WHERE group_name="guest"
                ';
                $permissions = $dbAdapter->fetchAll($sql);
 
                //set this to session, so that we will not be querying the db for every guest that is logged in.
                $guestSession->guestRoles = $permissions;
 
                //check for module ONLY - controller and action must be NULL
                for($i=0;$i</count><count ($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == NULL AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this module.');    
                        }
                }
 
                //check for controller+module - action is blank
                for($i=0;$i<count($permissions);$i++) {
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND
                        $permissions[$i]['action_name'] == NULL AND 
                        $permissions[$i]['permission'] == 'deny') {
                        throw new Exception('You are not allowed to access this controller.');    
                        }
                }
 
                //check for the module / controller / action - look for deny
                for($i=0;$i<count($permissions);$i++) {
                    //echo $permissions[$i]['module_name'].' '.$permissions[$i]['permission'].'<br>';
                    if ($permissions[$i]['module_name'] == $moduleName AND 
                        $permissions[$i]['controller_name'] == $controllerName AND 
                        $permissions[$i]['action_name'] == $actionName AND 
                        $permissions[$i]['permission'] == 'deny') {
 
                        throw new Exception('You are not allowed to access this page.');
                    }
                }
            }
            return true;
 
        } catch (Exception $e) {
            $this->getResponse()->setHttpResponseCode(403);
            $request->setControllerName('error');
            $request->setActionName('noaccess');
        }
    }
 
}
</count>

I know, lots of repition :P But I will refactoring this part when I have time. But I hope you got the idea of the entire thing.

Well, if you didn’t lemme explain it a bit.

First of all, the loginAction – logs in the user. It get the user details including the groups where the user is under. I have stored these details in the Session.

The CheckHasAccess Plugin gets called everytime someone loads a page. Plugins behave like this. Here are table structures for your reference.



-- 
-- Table structure for table `permissions`
-- 

CREATE TABLE `permissions` (
  `id` int(11) NOT NULL auto_increment,
  `group_id` int(11) NOT NULL,
  `group_name` varchar(250) NOT NULL,
  `module_name` varchar(250) default 'default',
  `controller_name` varchar(250) default NULL,
  `action_name` varchar(250) default NULL,
  `permission` enum('allow','deny') NOT NULL default 'allow',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;

-- 
-- Dumping data for table `permissions`
-- 

INSERT INTO `permissions` VALUES (1, 1, 'admin', 'default', 'admin', NULL, 'allow');
INSERT INTO `permissions` VALUES (3, 3, 'registereduser', 'default', 'admin', NULL, 'deny');
INSERT INTO `permissions` VALUES (7, 1, 'admin', 'default', 'index', NULL, 'allow');
INSERT INTO `permissions` VALUES (4, 2, 'moderator', 'default', 'admin', 'createsitevar', 'deny');
INSERT INTO `permissions` VALUES (5, 2, 'moderator', 'default', 'admin', 'managesitevars', 'deny');
INSERT INTO `permissions` VALUES (6, 2, 'moderator', 'default', 'admin', 'deletesitevar', 'deny');


-- 
-- Table structure for table `groups`
-- 

CREATE TABLE `groups` (
  `id` int(11) NOT NULL auto_increment,
  `group_name` varchar(250) NOT NULL,
  `group_desc` varchar(250) NOT NULL,
  `group_parent` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `group_name` (`group_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

-- 
-- Dumping data for table `groups`
-- 

INSERT INTO `groups` VALUES (1, 'admin', 'Administrators', 0);
INSERT INTO `groups` VALUES (2, 'moderators', 'Moderators', 0);
INSERT INTO `groups` VALUES (3, 'registereduser', 'Registered User / Member', 0);
INSERT INTO `groups` VALUES (4, 'guest', 'Guest', 0);

-- 
-- Table structure for table `user_group`
-- 

CREATE TABLE `user_group` (
  `id` bigint(20) NOT NULL auto_increment,
  `user_id` int(11) NOT NULL,
  `group_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

-- 
-- Dumping data for table `user_group`
-- 

INSERT INTO `user_group` VALUES (1, 1, 1);
INSERT INTO `user_group` VALUES (2, 2, 2);
INSERT INTO `user_group` VALUES (3, 3, 3);

This entry was posted in General and tagged , . Bookmark the permalink.

9 Responses to Zend Framework Zend_Auth and a Plugin to Check Access to a Page

  1. ben says:

    So.
    Ugly.

  2. simon says:

    Good! I like it.
    But how i can call the plugin everytime??
    I’m newbie..

    I think that add this line to my bootstrat file…
    $frontController->registerPlugin(new My_Controller_Plugin_CheckAccess());

    but the argument?? I don’t now..รน

    Tankyou

  3. Wenbert says:

    @simon you put something like this in your bootstrap file

    $frontController->registerPlugin(new Ekini_Controller_Plugin_CheckHasAccess());

    see http://framework.zend.com/manual/en/zend.controller.plugins.html for more info…

  4. simon says:

    Tanks, it work.

  5. Salman says:

    this has to be done by Zend_Auth/Zend_ACL.

  6. PixelMaker says:

    Hi,

    Nice example. Thanks for sharing it.

    I have more that one module like ‘admin’ , ‘technology’….

    Now, how can I call this plugin in each module (all controllers)?

    Is there a way to check HasAccess in bootstrap itself when we are in site.com/admin (or site.com/technology) like that?

    Thanks in Advance.

  7. Wenbert says:

    @PixelMaker, I am not sure I understand your question. But I think you would want to check the module and check if it “admin”. If it is, then you would “restrict” the user.

  8. Jagat says:

    Hi, Thanks a lot for excellent post.

Leave a Reply to Wenbert Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>