Hy,
for one of my projects I would like to use zend-navigation with Acl and an authorization middleware. But despite all my attempts I can not do it and at the same time could you tell me if it’s the right approach.
About zend-navigation I did this:
I have this in my configuration :
'acl' => [
'roles' => [
'visiteur' => [],
'membre' => ['visiteur'],
'administrateur' => ['membre'],
],
'resources' => [
'administrateur.action',
'membre.action',
'visiteur.action',
'login.action'
],
'allow' => [
'administrateur' => ['administrateur.action'],
'membre' => ['membre.action'],
'visiteur' => ['visiteur.action', 'login.action'],
],
'deny' => [
'administrateur' => ['login.action'],
'membre' => ['login.action'],
]
],
'navigation' => [
'menu_gauche' => [
[
'label' => 'Boite à outils',
'route' => 'outils',
'resource' => 'membre.action',
],
[
'label' => 'Administration',
'route' => 'admin',
'resource' => 'administrateur.action',
],
],
'menu_droit' => [
[
'label' => 'Connexion',
'route' => 'login',
'resource' => 'login.action',
],
[
'label' => 'déconnexion',
'route' => 'logout',
'resource' => 'membre.action',
],
],
],
'event_manager' => [
'lazy_listeners' => [
[
'listener' => Application\Listener\NavigationListener::class,
'method' => 'addAcl',
'event' => Zend\Mvc\MvcEvent::EVENT_RENDER,
'priority' => -100,
],
],
],
In my Module.php :
public function getServiceConfig()
{
return [
'factories' => [
Listener\NavigationListener::class => InvokableFactory::class,
Middleware\AuthorizationMiddleware::class => ConfigAbstractFactory::class,
],
];
}
/**
* {@inheritDoc}
* @see \Zend\ModuleManager\Feature\BootstrapListenerInterface::onBootstrap()
*/
public function onBootstrap(\Zend\EventManager\EventInterface $e)
{
$application = $e->getApplication();
$eventManager = $application->getEventManager();
$services = $application->getServiceManager();
$config = $application->getServiceManager()->get('config');
$eventManager->attach($e::EVENT_DISPATCH, function ($e) use ($services) {
$request = Psr7ServerRequest::fromZend($e->getRequest());
$response = Psr7Response::fromZend($e->getResponse());
$done = function ($request, $response) {
};
$authorizationMiddelware = $services->get(Middleware\AuthorizationMiddleware::class);
$result = $authorizationMiddelware(
$request->withAttribute('mvcEvent', $e),
$response,
$done
);
if ($result) {
return Psr7Response::toZend($result);
}
}, 2);
if (array_key_exists('event_manager', $config)
&& is_array($config['event_manager'])
&& array_key_exists('lazy_listeners', $config['event_manager'])
) {
$aggregate = new LazyListenerAggregate(
$config['event_manager']['lazy_listeners'],
$application->getServiceManager()
);
$aggregate->attach($application->getEventManager());
}
}
In my NavigationListener.php :
class NavigationListener
{
/**
* @param MvcEvent $event
*/
public function addAcl(MvcEvent $event)
{
$serviceManager = $event->getApplication()->getServiceManager();
/**
* @var \Zend\View\HelperPluginManager $helperPluginManager
*/
$helperPluginManager = $serviceManager->get('ViewHelperManager');
/**
* @var \Zend\View\Helper\Navigation $plugin
*/
$plugin = $helperPluginManager->get('navigation');
/**
* @var Acl $acl
*/
$acl = $serviceManager->get(AclFactory::class);
/**
* @var Container $session
*/
$session = $serviceManager->get(Session::class);
$role = ($session->offsetExists('role'))? $session->offsetGet('role') : 'visiteur';
$plugin->setDefaultAcl($acl);
$plugin->setRole($role);
$this->configureMenuHelper($plugin->menu());
}
private function configureMenuHelper(Menu $menu)
{
$menu->setPartial('partials/menu');
}
}
In my AuthorizationMiddleware.php :
class AuthorizationMiddleware
{
/**
* @var Acl
*/
private $acl;
/**
* @var Container
*/
private $session;
public function __construct(
Acl $acl,
Container $session
) {
$this->acl = $acl;
$this->session = $session;
}
public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next = null)
{
/**
* @var MvcEvent $mvcEvent
*/
$mvcEvent= $request->getAttribute('mvcEvent');
$role = ($this->session->offsetExists('role'))
? $this->session->offsetGet('role')
: 'visiteur';
$routeParam = $mvcEvent->getRouteMatch()->getParams();
$resource = (isset($routeParam['resource']))? $routeParam['resource'] : 'visiteur.action';
if (! $this->acl->isAllowed($role, $resource)) {
return new RedirectResponse('/login', 403);
}
}
}
With this code I get a blank page, and despite all my attempts I do not see how to return the correct answer from the authorization middleware,
Thank you in advance for your suggestions, advice or good practices.
PS: if you are missing code to help me to the solution do not hesitate.
cordially