|
Finally, I fixed it.
I did need some ticks and magic to get it done though. It isn't the most elegant solution but it does the trick. For others that might have the same problem a bit of explanation:
First of all, notice that the tutorial Alexander has made (which really is great and helped me out a lot) might not be exactly the same as what you might need in your website. In my case things are a bit different:
- my users have an array of roles instead of just one as a string
- my roles can't be hardcoded (except for my guest role which is an exception) since they come from the database
- some users are allowed certain priveleges depending on the resource, not just the role
- roles can conflict
- I used the assertions for the routing in my system, user (or guests) are allowed to go to a certain page depending on their role AND the assertion
Especially the last point is quite hard to solve in my case since a user has for example the priveleges to add a book, but not to edit or delete it. If you would look just at the roles you might never get to the page where the use can edit his own book details (which it is allowed to do->assertions)
Here is some relevant code I used:
/* accessCheck.php (plugin), as you can see I don't act on just the roles */
<?php
public function preDispatch(Zend_Controller_Request_Abstract $request){
$module = $request->getModuleName();
$controller = $request->getControllerName();
$resource = $module . ':' . $controller;
$action = $request->getActionName();
$allowed = FALSE;
$roles = Zend_Registry::get('userRoles');
foreach($roles as $id => $role_data){
if($this->_acl->isAllowed($role_data['role'], $resource, $action)){
$allowed = TRUE;
}
}
if(!$allowed){
Zend_Registry::set('Acl_Role_Allowed', FALSE);
}else{
Zend_Registry::set('Acl_Role_Allowed', TRUE);
}
$this->_acl->setDynamicPermissions();
}
?>
/* The assertion: */
<?php
public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null, $privelege = null){
if(Zend_Registry::get('Acl_Role_Allowed')){
return TRUE;
}else{
if($role->getUserId() == $resource->getOwnerId()){
return TRUE;
}else{
return FALSE;
}
}
}
?>
/* Adding a book: No assertion need, just the roles need to be checked */
<?php
public function addAction()
{
if(!Zend_Registry::get('Acl_Role_Allowed')){
if(Zend_Auth::getInstance()->hasIdentity()){
$this->_redirect('/');
}else{
$this->_redirect('/authentication/login');
}
}
etc.
}
?>
/* editting a book, if either a role or the user is allowed, there is no redirect */
<?php
public function editAction()
{
$userRole = new Model_Acl_UserRole();
$albumResource = new Administration_Model_Acl_Resource_Album();
$album_id = $this->_getParam('id', 0);
if($album_id > 0){
$albums = new Administration_Model_DbTable_Albums();
$data = $albums->getAlbum($album_id);
}else{
throw new Exception('Error with album id');
}
$albumResource->setOwnerId($data['user_id']);
if(!Zend_Registry::get('Acl_Role_Allowed') && !Zend_Registry::get('acl')->isAllowed($userRole, $albumResource, 'edit')){
if(Zend_Auth::getInstance()->hasIdentity()){
$this->_redirect('/');
}else{
$this->_redirect('/authentication/login');
}
}
etc.
}
?>
I actually don't like doing this much work in the controllers, but haven't found an easy work around to fix this. What I might do next:
- make one folder contain all the assertions.
- if the assertion file for a certain module, controller, privelege combination exists: handle the rest like I do above in the controller and assertion
- if the file does not exist: let the preDispatcher handle it (since it only depends on the roles).
Hope this helps anybody, if there is anybody that can make it all a bit more elegant, let me know!
|