-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Add RBAC support for navigation helper. #3693
Conversation
Mixing the two permissions systems into the same objects is... strange :/. As I told it on another issue, Zend\Navigation should be agnostic to any permission system. Check @spiffyjr implementation (this should have been the Zend\Navigation of ZF 2 but because of lack of time it wasn't integrated, but it shoudl for ZF 3): https://github.com/spiffyjr/spiffy-navigation And modules like ZfcRbac or BjyAuthorize will integrate the navigation to Rbac or Acl. I think this is a better idea than mixing. But as Zend\Navigation is a bit broken, may be we can afford this for ZF 2. |
@bakura10 |
The problem is is that there needs to be an "integrated" solution for the RBAC component. Otherwise, I would argue that the RBAC component should not have been included in the "core" of the framework. It's unreasonable to expect that users not assume that there be some level of integration between the RBAC component and navigation. It's not the cleanest solution to be sure but it is one that works. Is there a better alternative maybe? |
The Rbac component is pretty "useless" on its own, you should at least use ZfcRbac. Starting from here, it makes sense that all this integration work to be included into ZfcRbac instead than Zend\Navigation itself. Anyway, given the current state of Navigation, one more bad thing, maybe we can afford it... Let's wait for @weierophinney point of ivew. |
I use the ZfcRbac module myself. I don't know that there would be a way to provide any integration from the ZfcRbac component itself - unless you are proposing that the module include an alternative to the current implementation of the ZF2 Navigation component. This is the most flexible solution I have found so far but I am absolutely 100% open to a better alternative. This is how I go about things in my own application: $this->navigation('primary_navigation')
->menu()
->setUseAcl(false)
->setUseRbac(true)
->setPartial('partial/primary-menu.phtml')
->setRbac($this->rbacHelper()->getRbac())
->setRole($this->rbacHelper()->getIdentity()->getRoles()); (where "rbacHelper" is "ZfcRbac\Service\Rbac") This way, you're not coupling Navigation directly to the ZfcRbac module while still being able to leverage the power of the ZfcRbac module. |
Assuming that Acl has Thoughts? |
I don't think this is an appropriate solution; what happens if we add more permissions systems, each with their own APIs and requirements for determining validation? A better approach is to trigger an event -- let's call it "isAllowed" -- passing the page to the event; a listener can then return a boolean value indicating this status. This allows keeping the actual mechanism for determining rights separate from the navigation itself, while still providing the ability to provide access-specific navigation to users. @francisdaigle do you want to revise this PR to do that? or would you like somebody else to tackle it? |
+1 to the listener. We have events - let's use them where appropriate. :) |
The listener is a great idea 👍 |
Sounds great :) I'd be happy to put something together unless there is someone more appropriate for the task. |
Go for it, @francisdaigle! |
10-4 |
Alright. PR has been amended. Previous changes have been removed. Trigger for event listener ("isAllowed") has been added. Simple use case would be: ...
echo $this->navigation('primary_navigation')
->menu()
->setUseAcl(false)
->setPartial('partial/primary-menu.phtml'); ...
$eventManager->getSharedManager()->attach('Zend\View\Helper\Navigation\AbstractHelper', 'isAllowed', array('\Access\Listener\RbacListener', 'accept')); namespace Access\Listener;
class RbacListener
{
public function accept($event)
{
$serviceLocator = $event->getTarget()->getServiceLocator()->getServiceLocator();
$rbac = $serviceLocator->get('ZfcRbac\Service\Rbac');
$params = $event->getParams();
$page = $params['page'];
$permission = (string) $page->__get('permission');
$isGranted = $rbac->isGranted($permission);
return $isGranted;
}
} Does this work for everyone? @weierophinney? |
@francisdaigle This is looking good! Two comments:
Thoughts? |
Sounds good to me :) I'll put something together. |
@francisdaigle Any progress on tests? If you need help, jump into #zftalk.dev on Freenode IRC, and ask! Would love to see this in 2.2.0, as many folks are wanting RBAC support in navigation. :) |
Yeah, sorry - I'll try to get to this as soon as I can. Not enough hours in the day :) |
@weierophinney: Forthcoming :) |
@francisdaigle Why remove |
Thanks @danizord :) |
OK. ACL has been refactored (checks moved into listener). So, for the RBAC component, a simple use case would be: Setup the RBAC... namespace Application\Service;
use Zend\Permissions\Rbac\Rbac;
use Zend\Permissions\Rbac\Role;
class RbacService
{
protected $rbac;
public function getRbac() {
return $this->rbac;
}
public function setRbac($rbac) {
$this->rbac = $rbac;
}
public function __construct() {
$rbac = new Rbac();
$this->setRbac($rbac);
$member = new Role('member');
$member->addPermission('foo');
$this->getRbac()->addRole($member);
}
} Add the RBAC listener... namespace Application\Listener\Rbac;
use Application\Service\RbacService;
use Zend\EventManager\Event;
class AcListener
{
public function accept(Event $event)
{
$event->stopPropagation();
$accepted = true;
$rbacService = new RbacService();
$rbac = $rbacService->getRbac();
$params = $event->getParams();
$page = $params['page'];
$permission = $page->getPermission();
if ($permission) {
$accepted = $rbac->isGranted('member', $permission);
}
return $accepted;
}
} Attach the listener... ...
class Module
{
public function onBootstrap()
{
$eventManager->getSharedManager()->attach('Zend\View\Helper\Navigation\AbstractHelper', 'isAllowed', array('Application\Listener\Rbac\AcListener', 'accept'));
}
}
... And lastly... ...
echo $this->navigation('navigation')->menu();
... That's it. Because "$setUseAcl = true" by default there is no need for any additional flags. Just override the default listener and stop the event from propagating like in the example above (ie. $event->stopPropagation()). Does this work for everyone? @weierophinney? |
@@ -886,4 +916,18 @@ public static function setDefaultRole($role = null) | |||
)); | |||
} | |||
} | |||
} | |||
|
|||
protected function setDefaultListeners() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a docblock (I'll supply this when I merge)
[WIP] Add RBAC support for navigation helper.
- Docblock additions/edits - Logic workflow
- trailing whitespace - EOF endings
…e/develop [WIP] Add RBAC support for navigation helper.
- trailing whitespace - EOF endings
…e/develop [WIP] Add RBAC support for navigation helper.
- Docblock additions/edits - Logic workflow
- trailing whitespace - EOF endings
…e/develop [WIP] Add RBAC support for navigation helper.
- trailing whitespace - EOF endings
Permissions-based navigation support for RBAC component.