📜 ⬆️ ⬇️

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

The second part of the article about introducing Zend_Acl in MVC by Aldemar Bernal appeared on DevZone and I hasten to offer you its translation.

In the first part, we talked about how to set up an instance of Zend_Acl and include it in the MVC environment (using the front controller plugin). But how to configure other actions to block access, or how to make editing the article only by its author? This and something else will be discussed further.


')
As I said in the first part, this article is based on the following sentence , which is currently in the research stage.

1. Using Modules


Let's talk about the modules. As an example for this article, we took a site like DevZone. And what if we create an administrative module whose task is to implement the procedure for approving articles. In addition, the module can implement a number of tasks, such as managing short links or categories. In this case, we will have to change our resource model:

Common module
  1. User Controller.
  2. Controller articles.

Administrative module
  1. Controller articles.
  2. Controller short links.
  3. Category controller.

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

Note : Remember that this code and the creation of an instance of a Zend_Acl object must be executed before calling the front controller's dispatch method (at boot time).
  / ** 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 (); 


I note that, as before, we have created a resource for each controller. But in the case of the administrator module, we created a resource for the module and one for each controller inside this module in the “module: controller” format, making them descendants of the module resource. We also made the Administrator role the only one allowed access to the entire administration module.

2. Using roles


Once the user has entered the application, he should get the role. In our example, this role can be “guest”, “author”, or “administrator”. But how can we change the current ACL role in our component? First, you must save this role in a variable that is in session space. Thus, as soon as the user logs in, you must save the user role in the session. On the next request, you will take this variable from the session and use it to configure the front controller plug-in during the boot phase.

User Controller
  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;
     }
 } 

Loader file
  / ** 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 (); 


3. Setting the action for the error "access denied"


Maybe some of you (I hope no one = D) just do not like the idea of ​​having the “Access Denied” action in the error controller, or just want to call it something else. This can be done by calling the front controller plugin's setErrorPage method.

  / ** 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 (); 

The setErrorPage method can be called with only the name of the action. In this case, the controller and the module will remain “error” and “default”. The same method can be called by passing the names of the action and the controller, or by passing all three parameters.

4. Using the action helper


Finally, we will see one of the most important parts of this sentence. Until now, in our DevZone example, we have seen that we allow administrators and authors to edit articles. But wait, there is still a missing part of our application. Now, if I am an author and have access to article / edit /: id, this means that I have access to editing not only my articles, but also articles of other authors! This is not very good, is it? So what are we going to do about it? We will manage this using an action helper, which means that you can access our ACLs within any controller, and not just at boot time.

So, the first thing we do is register not only our front controller controller plugin, but also our action assistant in the Broker of action controller assistants.

Loader file
  / ** 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 an assistant, we can use it inside any controller. Let's give change access rights only to the owner or any administrator.

Article controller
  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 Admin
         if (($ article-> author! = $ this -> _ application-> loggedUser)
              && ($ this -> _ application-> currentRole! = 'admin')) {
             $ this -> _ acl-> denyAccess ();
         } 

         ...
     }
 } 


Conclusion


Some lovers of garbage in the trash all their lives trying to find the missing link (and they will die in the search for it) and some ZF-eryy old in trying to get the ACL to work properly in their MVC environment. I hope the proposal expressed above may be one of the missing pieces in the world of ACL + MVC.

In conclusion, I want to give a recommendation. Adhere to the principle “Make it easier”: if you don’t need to have a dynamic ACL load, then manually loading and configuring it is not at all a sin, perhaps this is the best way to act in this situation.

For more information on the topic, you can read the following:
Zend_Acl & MVC Integration
and a small example of the implementation of the approach described in the article:
Source code

Crosspost: http://lobach.info/develop/zf/zend_acl-and-mvc-integration-part-2/

Source: https://habr.com/ru/post/31644/


All Articles