问题
I am working on Album Application in zf3.I added acl functionality to the application like this:
AlbumController.php
class AlbumController extends AbstractActionController
{
protected $role;
public function onDispatch(\Zend\Mvc\MvcEvent $e)
{
$userSession = new Container('user');
if (!isset($userSession->email)) {
return $this->redirect()->toRoute('login');
}
else {
$this->role = $userSession->role;
parent::onDispatch($e);
}
}
public function checkPermission($role,$action)
{
if($role == 'admin'){
$acl = new Acl();
if ($acl->isAllowed('admin', 'AlbumController', $action)) {
return true;
}
}
return false;
}
public function editAction()
{
$action = 'edit';
$permission = $this->checkPermission($this->role,$action);
if (!$permission) {
$this->flashMessenger()->addMessage('<div class="alert alert- danger" role="alert"><b>You dont have the privilege to edit!!</b></div>');
return $this->redirect()->toRoute('album');
}
$id = (int) $this->params()->fromRoute('id', 0);
if (0 === $id) {
return $this->redirect()->toRoute('album', ['action' => 'add']);
}
try {
$album = $this->table->getAlbum($id);
} catch (\Exception $e) {
return $this->redirect()->toRoute('album', ['action' => 'index']);
}
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
$viewData = ['id' => $id, 'form' => $form];
if (! $request->isPost()) {
return $viewData;
}
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
$edit = $request->getPost('submit', 'Cancel');
if($edit == 'Cancel'){
$this->flashMessenger()->addMessage('<div class="alert alert-danger" role="alert"><b>Cancelled by User...!!</b></div>');
return $this->redirect()->toRoute('album');
}
if (! $form->isValid()) {
$this->flashMessenger()->addMessage('<div class="alert alert-danger" role="alert"><b>Failed to Update...!!</b></div>');
return $viewData;
}else{
$this->table->saveAlbum($album);
$this->flashMessenger()->addMessage('<div class="alert alert-success" role="alert"><b>Record Updated Successfully...!!</b></div>');
}
// Redirect to album list
return $this->redirect()->toRoute('album', ['action' => 'index']);
}
}
This is working perfectly fine,now i want to move the onDispatch function to Module.php but don't know how to implement it.Can someone please help me
Module.php
<?php
namespace Album;
use Album\Controller\AlbumController;
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Album\Model\LoginTable;
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function getServiceConfig()
{
return [
'factories' => [
AlbumTable::class => function($container) {
$tableGateway = $container->get(Model\AlbumTableGateway::class);
return new AlbumTable($tableGateway);
},
Model\AlbumTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
Model\LoginTable::class => function($container) {
$tableGateway = $container->get(Model\LoginTableGateway::class);
$table = new LoginTable($tableGateway);
return $table;
},
Model\LoginTableGateway::class => function ($container){
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
return new TableGateway('login', $dbAdapter, null, $resultSetPrototype);
}
],
];
}
public function getControllerConfig()
{
return [
'factories' => [
Controller\AlbumController::class => function($container) {
return new Controller\AlbumController($container->get(Model\AlbumTable::class));
},
Controller\LoginController::class => function($container) {
return new Controller\LoginController($container->get(Model\LoginTable::class));
},
Controller\LogoutController::class => function($container){
return new Controller\LogoutController($container->get(Model\LoginTable::class));
},
],
];
}
}
回答1:
This is how I implemented it. In your Module.php
, add a listener on EVENT_DISPATCH
, with a closure as callback that will call your middleware class authorization :
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$eventManager = $app->getEventManager();
$serviceManager = $app->getServiceManager();
// Register closure on event DISPATCH, call your checkProtectedRoutes() method
$eventManager->attach(MvcEvent::EVENT_DISPATCH, function (MvcEvent $e) use ($serviceManager) {
$match = $e->getRouteMatch();
$auth = $serviceManager->get(Middleware\AuthorizationMiddleware::class);
$res = $auth->checkProtectedRoutes($match);
if ($res instanceof Response) {
return $res;
}
}, 1);
// Init ACL : could be improved
$this->initAcl($e);
}
You should have an AuthorizationMiddlewareFactory
(call it as you want):
<?php
namespace MyModule\Factory;
use Interop\Container\ContainerInterface;
use MyModule\Middleware\AuthorizationMiddleware;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;
class AuthorizationMiddlewareFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$authService = $container->get(AuthenticationService::class);
$acl = $container->get('Acl'); // II init it in bootstrap(), could be improved
$response = $container->get('Response');
$baseUrl = $container->get('Request')->getBaseUrl();
$authorization = new AuthorizationMiddleware($authService, $acl, $response, $baseUrl);
return $authorization ;
}
}
And your AuthorizationMiddleware
class:
<?php
namespace MyModule\Middleware;
use Symfony\Component\VarDumper\VarDumper;
use Zend\Authentication\AuthenticationService;
use Zend\Http\PhpEnvironment\Response;
use Zend\Permissions\Acl\Acl;
use Zend\Router\RouteMatch;
class AuthorizationMiddleware
{
private $authService ;
private $acl;
private $response;
private $baseUrl;
/**
* AuthorizationMiddleware constructor.
* @param AuthenticationService $authService
* @param Acl $acl
* @param Response $response
* @param $baseUrl
*/
public function __construct(AuthenticationService $authService, Acl $acl, Response $response, $baseUrl)
{
$this->authService = $authService;
$this->acl = $acl;
$this->response = $response;
$this->baseUrl = $baseUrl;
}
public function checkProtectedRoutes(RouteMatch $match)
{
if (! $match) {
// Nothing without a route
return null ;
}
// Do your checks...
}
It can be improved, but you have the idea... See also this Question and the answers: ZF3 redirection after ACL authorization failed
来源:https://stackoverflow.com/questions/39721284/how-to-implement-acl-and-authorization-in-module-php-in-zf3