Zend_Acl + Zend_Auth + Zend_Controller_Plugin = HAPPY!
Before I start explaining the code let me just give it to you!
Users SQL
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) NOT NULL, `userpassword` varchar(40) NOT NULL, `firstname` varchar(255) NOT NULL, `lastname` varchar(255) NOT NULL, `role` varchar(30) NOT NULL DEFAULT 'user', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
/application/configs/application.ini
autoloaderNamespaces[] = "Application_" resources.frontController.plugins.Acl = "Application_Controller_Plugin_Acl" acl.roles.guest = null acl.roles.user = guest acl.roles.admin = user acl.resources.allow.index.all = guest acl.resources.allow.error.all = guest acl.resources.allow.user.register = guest acl.resources.allow.user.login = guest acl.resources.allow.user.profile = user
/library/Application/Acl.php
<?php
class Application_Acl extends Zend_Acl {
public function __construct(Zend_Config $config){
$roles = $config->acl->roles;
$resources = $config->acl->resources;
$this->_addRoles($roles);
$this->_addResources($resources);
}
private function _addRoles($roles){
foreach($roles as $name => $parents){
if(!$this->hasRole($name)) {
if(empty($parents)){
$parents = array();
} else {
$parents = explode(',', $parents);
}
$this->addRole(new Zend_Acl_Role($name), $parents);
}
}
}
private function _addResources($resources){
foreach($resources as $permissions => $controllers){
foreach($controllers as $controller => $actions){
if('all' == $controller){
$controller = null;
} else {
if(!$this->has($controller)){
$this->add(new Zend_Acl_Resource($controller));
}
}
foreach($actions as $action => $role){
if($action == 'all') {
$action = null;
}
if($permissions = 'allow'){
$this->allow($role, $controller, $action);
}
if($permissions == 'deny'){
$this->deny($role, $controller, $action);
}
}
}
}
}
}
/library/Application/Controller/Plugin/Acl.php
<?php
class Application_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request){
// Load ACL config
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
$acl = new Application_Acl($config);
// Begin authorisation
$auth = Zend_Auth::getInstance();
$role = 'guest';
if($auth->hasIdentity()){
$user = $auth->getIdentity();
print_r($user);
if(is_object($user)){
$role = $user->role;
}
}
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
$resource = $controller;
$privellege = $action;
if(!$acl->has($resource)) {
throw new Exception('No resource found');
}
if(!$acl->isAllowed($role, $resource, $privellege)) {
$request->setModuleName('default')
->setControllerName('user')
->setActionName('login')
->setDispatched(false);
}
}
}
/application/controllers/UserController.php
<?php
class UserController extends Zend_Controller_Action
{
public function indexAction(){
// action body
}
public function logoutAction(){
$auth = Zend_Auth::getInstance();
$auth->clearIdentity();
}
public function loginAction() {
$form = $this->_helper->formLoader('login');
if ($this->getRequest()->isPost()) {
if (! $form->isValid($_POST)) {
$this->view->form = $form;
return;
} else {
$data = $form->getValues();
$authAdapter = new Zend_Auth_Adapter_DbTable(Zend_Db_Table::getDefaultAdapter());
$authAdapter->setTableName('user')->setCredentialColumn('userpassword')->setIdentityColumn('email')->setCredentialTreatment('MD5(?)');
$authAdapter->setIdentity($data['email']);
$authAdapter->setCredential($data['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
$userInfo = $authAdapter->getResultRowObject(null, array('userpassword'));
$authStorage = $auth->getStorage();
$authStorage->write($userInfo);
} else {
}
}
}
$this->view->form = $form;
}
public function registerAction(){
$form = $this->_helper->formLoader('register');
if($this->getRequest()->isPost()){
if(!$form->isValid($_POST)){
$this->view->form = $form;
return;
}
}
$this->view->form = $form;
}
}
So that’s the code, cudos has to go to Joe Topjian for giving me the idea and the base code to work from…
| Print article | This entry was posted by Gavin Williams on August 3, 2009 at 3:43 pm, and is filed under PHP, Zend Framework. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 7 months ago
Sorry for my bad English.
Init “$acl = new Application_Acl($config);” in method preDispatch bad good idea.
Because, when you call Zend_Controller_Action::_forward, you init your Acl several.
about 7 months ago
Init in the method __construct from class your Plugin
about 7 months ago
Just wanted to drop you a line to say thanks for helping me wrap my brain around this. I was struggling with exactly the same criteria as you (especially the piss easy bit), and this post helped me finally nail it.
good work!
about 6 months ago
Interesting article, however I found that this prevents my 404 page from working.
So if i type in /foo (a non-existing controller) it just redirects to the login page.
Any ideas?
Ben
about 6 months ago
Never mind I figured this out.
In the example code if a resource is not found the resource is set to null. In my circumstance this is the 404 condition.
So rather than setting the resource to null, i throw an exception which is handled by the error controller.
Anyhew, thanks for the above very useful.
about 6 months ago
It’s no problem, I’m glad this helped demystify this somewhat! I’ve amended the article so that it throws an exception now.
about 6 months ago
There is also an easier way to access your application.ini file through the bootstrap!
about 6 months ago
Right now I have the acl in it’s own config. I load the config and the model in the bootstrap then save the acl model to the registry so I can use it in my Access plugin.
I need to set up caching for this since I think parsing this file all the time might be a performance hit. Especially when it gets big.
The odd thing is, I did not think setting a model would work in the boostrap because it is invoked before the app knows about the models (at least that is what I thought).
protected function _initAcl() {
$aclConfig = new Zend_Config_Ini(APPLICATION_PATH . ‘/configs/acl.ini’, APPLICATION_ENV);
$aclModel = new Model_Acl($aclConfig);
Zend_Registry::set(‘aclModel’, $aclModel);
}
To be safe I think I will move the model instantiation and caching to my Access plugin. This will also keep all the acl stuff more centrally located.
Fun! fun!
about 5 months ago
You have a small typo in /library/Application/Acl.php on line 42, it should be if($permissions == ‘allow’) instead of if($permissions = ‘allow’)
about 4 months ago
He there
first of all thnx for this one it made several things clear
but i still have a question, how can you combine this with zend_navigation?
I need some links be hidden if the user is ‘guest’
thnx !
about 3 months ago
Thanks for this.
There is also another small typo. In /library/Application/Controller/Plugin/Acl.php you can remove the print_r on line 17.
KUTGW!
about 3 months ago
Hey.
Thanks for this great tut.
I’m just having a small issue.
Once the AclPlugin is registered to the front controller, I’m getting this error:
Fatal error: Cannot redeclare class Application_Acl in /Applications/MAMP/htdocs/…/library/Application/Acl.php on line 58
Any idea why?
Thanks.
about 3 months ago
Nevermind I found the solution.
What about redirecting a denied role to a denied action in the error controller instead of redirecting to the login page?
about 1 month ago
You must also add in your application.ini:
acl.resources.allow.user.logout = guest
Withou this, you can’t logout.