Integration of Zend_Acl and MVC. Part 2 (advanced use)

DevZone appeared the second part of the article about integration of Zend_Acl into MVC Aldemar Bernal and I hasten to offer you its translation.

first part we talked about how to configure an instance of Zend_Acl and include it in MVC (using the plugin from the front controller). But how do you configure other actions to block access, or how to do the edit articles only the author? This something else will be discussed later.



As I said in the first part, this article is based on the following the proposal, which is currently in the research phase.

the

1. Using modules


Let's talk about modules. As an example, for this article we took a website like Devzone. What if we create an administration module, whose task is to implement procedures for the approval of articles. Additionally, a module can implement a number of tasks such as management of short links, or categories. In this case we have to change our resource model:

the Common module
    the
  1. Controller users.
  2. the
  3. Controller articles.

the administration module
    the
  1. Controller articles.
  2. the
  3. Controller short link.
  4. the
  5. the Controller.

Based on this new resource model, we create an instance of Zend_Acl, which will reflects it.

the note: remember that this code and create an object instance, Zend_Acl must be fulfilled before a method call dispatching the front controller (at boot time).
the
/** Creating Roles */ 
require_once 'Zend/Acl/Role.php'; 
$myAcl- > addRole(new Zend_Acl_Role('guest')) 
->addRole(new Zend_Acl_Role('writer'), 'guest') 
->addRole(new Zend_Acl_Role('admin'), 'writer'); 

/** Creating resources */ 
require_once 'Zend/Acl/Resource.php'; 
/** Default module */ 
$myAcl- > add(new Zend_Acl_Resource('user')) 
- >add(new Zend_Acl_Resource('article')); 

/** Admin module */ 
$myAcl- > add(new Zend_Acl_Resource('admin')) 
- >add(new Zend_Acl_Resource('admin:article', 'admin')) 
- >add(new Zend_Acl_Resource('admin:quick-link', 'admin')) 
- >add(new Zend_Acl_Resource('admin:category', 'admin')); 

/** Creating permissions */ 
$myAcl- > allow('guest', 'user') 
->deny('guest', 'article') 
->allow('guest', 'article', 'view') 
->allow(array('writer', 'admin'), 'article', array('add', 'edit')) 
->allow('admin', 'admin'); 

/** Setting up the front controller */ 
require_once 'Zend/Controller/Front.php'; 
$front = Zend_Controller_Front::getInstance(); 
$front- > setControllerDirectory(array('default' => 'path/to/default/controllers', 
'admin' => 'path/to/admin/controllers')); 

/** Registering the Plugin object */ 
require_once 'Zend/Controller/Plugin/Acl.php'; 
$front- > registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, 'guest')); 

/** Dispatching the front controller */ 
$front->dispatch();


Note that as before, we have created a resource for each controller. But in the case of the admin module, we created a resource for the module and one for each controller in this module in the format "module: controller", making them the descendants of the resource module. We also did the role of the Administrator is the only person allowed access to the administration module.

the

2. Uses of roles


Once the user has logged in, he should get the role. In our example, this role may be a "guest", "author" or "administrator". But how can we change the current ACL role in our component? First, you need to maintain this role in the variable that are in session. Thus, once a user logs in, you need to save the user role in the session. At the next prompt, you will take this variable from the session and use it to configure the plugin with the front controller during the loading phase.

the users Controller
the
class UserController extends Zend_Controller_Action 
{ 
protected $_application; 

public function init() 
{ 
require_once 'Zend/Session/Namespace.php'; 
$this- > _application = new Zend_Session_Namespace('myApplication'); 
} 

public function loginAction() 
{ 
... Validation code 
if ($valid) { 
/** Setting role into session */ 
$this- > _application- > currentRole = $user- > role; 
$this- > _application- > loggedUser = $user- > username; 
} 


public function logoutAction() 
{ 
$this- > _application- > currentRole = 'guest'; 
$this- > _application- > loggedUser = null; 
} 
}

the File Downloader
the
/** Loading application from session */ 
require_once 'Zend/Session/Namespace.php'; 
$application = new Zend_Session_Namespace('myApplication'); 

if (!isset($application- > currentRole)) { 
$application- > currentRole = 'guest'; 
} 

/** Setting up the front controller */ 
require_once 'Zend/Controller/Front.php'; 
$front = Zend_Controller_Front::getInstance(); 
$front- > setControllerDirectory('path/to/controllers'); 

/** Registering the Plugin object */ 
require_once 'Zend/Controller/Plugin/Acl.php'; 
$front- > registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application- > currentRole)); 

/** Dispatching the front controller */ 
$front->dispatch();


the

3. Setting the error alert "deny access"


Maybe some of you (I hope no one =D) just don't like the idea of having the action "Access denied" in the error controller, or just want to call him any differently. This can be done by calling the method setErrorPage plugin from the front controller.

the
/** Setting up the front controller */ 
require_once 'Zend/Controller/Front.php'; 
$front = Zend_Controller_Front::getInstance(); 
$front- > setControllerDirectory('path/to/controllers'); 

/** Setting default access denied action */ 
require_once 'Zend/Controller/Plugin/Acl.php'; 
$aclPlugin = new Zend_Controller_Plugin_Acl($myAcl, 'guest'); 
$aclPlugin- > setErrorPage('goaway', 'my-error-controller', 'my-module'); 

/** Registering the Plugin object */ 
$front- > registerPlugin($aclPlugin); 

/** Dispatching the front controller */ 
$front->dispatch();

SetErrorPage method can be invoked specifying only the name of the action. In this case, the controller and the module will remain "error" and "default". The same method can be invoked by name passing action and controller, or by passing all three parameters.

the

4. The use of helper actions


Finally, we will see one of the most important parts of this proposal. Still in our example Devzone we have seen that we allow administrators and authors to edit articles. But wait, there's still the missing piece of our application. Now if I am the author and have access to the article/edit/:id, it means that I have access to edit not only their articles, but also articles of other authors! It's not very good, right? So, what are we going to do? We will manage this using the action helper, and it means that you will be able to access our ACL inside any controller and not only at boot time.

So the first thing we do is register our plugin to the front controller, but also our action helper to the helper Broker action controller.

the File Downloader
the
/** Loading application from session */ 
require_once 'Zend/Session/Namespace.php'; 
$application = new Zend_Session_Namespace('myApplication'); 

if (!isset($application- > loggedUser)) { 
$application- > loggedUser = null; 
} 

/** Setting up the front controller */ 
require_once 'Zend/Controller/Front.php'; 
$front = Zend_Controller_Front::getInstance(); 
$front- > setControllerDirectory('path/to/controllers'); 

/** Registering the Plugin object */ 
require_once 'Zend/Controller/Plugin/Acl.php'; 
$front- > registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application- > currentRole)); 

/** Registering the Action Helper object */ 
require_once 'Zend/Controller/Action/Helper/Acl.php'; 
require_once 'Zend/Controller/Action/HelperBroker.php'; 
Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_Acl()); 

/** Dispatching the front controller */ 
$front->dispatch();

And after registering the helper, we can use it inside any controller. Let's give the access rights to change only the owner or any administrator.

the Controller articles
the
class ArticleController extends Zend_Controller_Action 
{ 
protected $_acl; 
protected $_application; 

public function init() 
{ 
/** Get our Action Helper */ 
$this->_acl = $this->_helper->getHelper('acl'); 

require_once 'Zend/Session/Namespace.php'; 
$this- > _application = new Zend_Session_Namespace('myApplication'); 
} 

... 

public function editAction() 
{ 
/** Load article by id */ 
$article = new Article($this->_request->id); 

/** Validate if the user is the owner or an Admin */ 
if (($article- > author != $this- > _application- > loggedUser) 
&& ($this- > _application- > currentRole != 'admin')) { 
$this->_acl- > denyAccess(); 
} 

... 
} 
}


the

Conclusion


Some fans swarm in the trash my whole life trying to find the missing link (and they will die in the pursuit of it) and some MF-ers grow old in trying to get ACL to work properly in their MVC environment. Hope expressed by the above sentence, it may be one of the missing pieces in the world ACL + MVC.

In conclusion, I want to give a recommendation. Stick to the principle of "Make easier": if you don't really need dynamic loading of the ACL, it download and configure manually — is not a sin, it may be the best course of action in this situation.
For more detailed familiarization with the topic, you can read the following:
Zend_Acl &MVC Integration
and a small sample implementation of the approach described in the article:
Source Code

Crosspost: http://lobach.info/develop/zf/zend_acl-and-mvc-integration-part-2/
Article based on information from habrahabr.ru

Comments

Popular posts from this blog

Powershell and Cyrillic in the console (updated)

Active/Passive PostgreSQL Cluster, using Pacemaker, Corosync

Automatic deployment ElasticBeanstalk using Bitbucket Pipelines