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 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);
So.
Ugly.
Heh.
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
@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…
Tanks, it work.
this has to be done by Zend_Auth/Zend_ACL.
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.
@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.
Hi, Thanks a lot for excellent post.