In this tutorial you will learn how to setup zend framework 2 acl and check if user has access for current route.
If you don`t have testing project , download one from here.
Add file module.acl.roles in application/config/
Tip: In fact role resources may be zend framework 2 routes.
return array(
'guest'=> array(
'home',
'login',
'register'
),
'admin'=> array(
'admin',
'add-user',
'delete-user'
),
);
Code in application/module.php
public function onBootstrap(MvcEvent $e) {
$this -> initAcl($e);
$e -> getApplication() -> getEventManager() -> attach('route', array($this, 'checkAcl'));
}
public function initAcl(MvcEvent $e) {
$acl = new \Zend\Permissions\Acl\Acl();
$roles = include __DIR__ . '/config/module.acl.roles.php';
$allResources = array();
foreach ($roles as $role => $resources) {
$role = new \Zend\Permissions\Acl\Role\GenericRole($role);
$acl -> addRole($role);
$allResources = array_merge($resources, $allResources);
//adding resources
foreach ($resources as $resource) {
// Edit 4
if(!$acl ->hasResource($resource))
$acl -> addResource(new \Zend\Permissions\Acl\Resource\GenericResource($resource));
}
//adding restrictions
foreach ($allResources as $resource) {
$acl -> allow($role, $resource);
}
}
//testing
//var_dump($acl->isAllowed('admin','home'));
//true
//setting to view
$e -> getViewModel() -> acl = $acl;
}
public function checkAcl(MvcEvent $e) {
$route = $e -> getRouteMatch() -> getMatchedRouteName();
//you set your role
$userRole = 'guest';
if (!$e -> getViewModel() -> acl -> isAllowed($userRole, $route)) {
$response = $e -> getResponse();
//location to page or what ever
$response -> getHeaders() -> addHeaderLine('Location', $e -> getRequest() -> getBaseUrl() . '/404');
$response -> setStatusCode(404);
}
}
Edit 1
I am assuming that all the routes that are accessed in the app are already added to the acl config file.
If not replace :
if (!$e -> getViewModel() -> acl -> isAllowed($userRole, $route)) {
to
if ($e -> getViewModel() -> acl ->hasResource($route) && !$e -> getViewModel() -> acl -> isAllowed($userRole, $route)) {
Edit 2
If access inheritance is not needed just replace this :
//$allResources = array_merge($resources, $allResources);
foreach ($allResources as $resource) {
// with
foreach ($resources as $resource) {
Edit 3
But what about acl from the database someone will say ?
In the zend framework 2 startup tutorial they say – “Don`t go heavy in onBootstrap”
With that said , I think that an array file will work for most of the cases.
Add this method where acl check is
public function getDbRoles(MvcEvent $e){
// I take it that your adapter is already configured
$dbAdapter = $e->getApplication()->getServiceManager()->get('Zend\Db\Adapter\Adapter');
$results = $dbAdapter->query('SELECT * FROM acl');
// making the roles array
$roles = array();
foreach($results as $result){
$roles[$result['user_role']][] = $result['resource'];
}
return $roles;
}
Then replace in initAcl
// this
$roles = include __DIR__ . '/config/module.acl.roles.php';
// with
$roles = $this->getDbRoles($e);
Simple as that.
Suggestions or problems ? Write a comment.