可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am writing a module for ACL
in ZF2
, And I am almost done with it.
The point where I am stucked is when user is not authorised to access the requested page, I want to forward the user to a page showing 403
message.
I have tried redirecting user to 403
but it updates URL
, so now I am tring to forward user.
All I want to do is from Module.php
. I have tried below code -
Module.php
if (!$isAllowed) {
$e->getApplication()->getServiceManager()->get('ControllerPluginManager')->get('forward')->dispatch('acl');
}
Using this I got following error -
Uncaught exception 'Zend\Mvc\Exception\DomainException' with message 'Forward plugin requires a controller that implements InjectApplicationEventInterface'
I have also tried to implement Acl
controller with InjectApplicationEventInterface
, But the issue remains same.
Can you please explain how to Forward
to another Action
from Module.php
?
Let me know if you need more details.
回答1:
What you can do is to listen for the dispatch event. You can update the route match during this event to match a controller/action pair which is defined by yourself to render the 403 page.
In code:
use MvcEvent;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$acl = $app->getServiceManager()->get('ACL'); // get your ACL here
if (!$acl->isAllowed()) {
$em = $app->getEventManager();
$em->attach(MvcEvent::EVENT_DISPATCH, function($e) {
$routeMatch = $e->getRouteMatch();
$routeMatch->setParam('controller', 'my-403-controller');
$routeMatch->setParam('action', 'my-403-action');
}, 1000);
}
}
}
Forwarding is a pattern to dispatch a controller when another controller has already been dispatched. That is not your case, as I read it from your question. So don't use the forward plugin, but modify the route match before it's dispached.
回答2:
You can not forword but redirect to your 403 page as follow:
if (!$acl->isAllowed()) {
$response = $e->getResponse();
$response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseUrl() . '/403page');
$response->setStatusCode(403);
}
回答3:
I think that if you want to send information to user that he is in restricted zone without the update of url you have to:
- Change layout which shows restricted area message.
- Leave original layout and just switch templates for your action so it shows restricted area message.
After one of this actions you just change Response to 403.
If that`s what you want its simple to do. For any action in your controller you want to send 403 status just use:
$viewModel->setTemplate('partial/noRights');
$this->getResponse()->setStatusCode('403');
return $viewModel;
or if you want to change layout for your custom one:
$this->layout('layout/custom');
$this->getResponse()->setStatusCode('403');
return $viewModel;
You can of course do it to in bootstrap section of your module adding listener on event_dispatch and there check if $acl->isAllowed() after that do your changes which i wrote above. Example:
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$acl = $app->getServiceManager()->get('ACL'); // get your ACL here
if (!$acl->isAllowed()) {
$eventManager = $app->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
$sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH, function($e) {
$controller = $e->getTarget(); //controller`s action which triggered event_dispatch
$controller->getResponse()->setStatusCode('403');
$controller->layout('layout/custom');
}, 1000);
}
}
回答4:
When I implemented ACL,
I created my own AUTH module for authorization and authentication.
In that module I created ACL plugin.. something like below
//Module.php
/**
* This method is called once the MVC bootstrapping is complete
*
* @param \Zend\EventManager\EventInterface $e
*/
public function onBootstrap(Event $e)
{
$services = $e->getApplication()->getServiceManager();
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach('dispatch', array($this, 'loadConfiguration'), 101);
}
/**
*
* @param \Zend\Mvc\MvcEvent $e
*/
public function loadConfiguration(MvcEvent $e)
{
$e->getApplication()->getServiceManager()
->get('ControllerPluginManager')->get('AclPlugin')
->checkAcl($e); //Auth/src/Auth/Controller/AclPlugin
}
//Auth/src/Auth/Controller/AclPlugin
namespace Auth\Controller\Plugin;
/**
* load libraries here
*/
class AclPlugin extends AbstractPlugin implements ServiceManagerAwareInterface
{
/*
* @var Doctrine\ORM\EntityManager
*/
protected $em;
protected $sm;
/**
* @param Doctrine\ORM\EntityManager $em
* @return string
*/
public function checkAcl($e)
{
$matches = $e->getRouteMatch();
$controller = $matches->getParam('controller');
$action = $matches->getParam('action', 'index');
if ($acl->isAllowed($role, $resource, $permission)) {
return;
} else {
$matches->setParam('controller', 'Auth\Controller\User'); // redirect
$matches->setParam('action', 'accessdenied');
return;
}
}
/// rest of the code here
}