-
Notifications
You must be signed in to change notification settings - Fork 0
Dev.Module Authorization
Introduction
Creating configuration files
Usage of Pi\Acl\Acl class
A Simple Case To Use Authorization in Module
Authorization or Permission management is an important section of website. It mainly contains user roles definition, resources definition, and authorization distribution. In this user guide, we will introduce the following content:
- Module configuration creation for defining roles, resources and permission.
- Using
Pi\Acl\Acl
to add rules and check permission.
Pi use acl.php
and page.php
to define roles, resources and rules. Therefore users must first create the configuration files of module in the config
folder.
config\acl.php
The array structure of acl.php must be like the following:
return array(
// Definition roles
'roles' => array(
// Case 1
'roleName' => array(
'title' => 'Title',
'parents' => array('parent'),
),
// Case 2
'admin' => array(
'title' => __('Administrator'),
'section' => 'admin',
),
// Case 3
'staff' => array(
'title' => __('Staff'),
'section' => 'admin',
),
// Case 4
'manager' => array(
'title' => __('Manager'),
'section' => 'admin',
'parents' => array('admin', 'staff'),
),
...
),
// Definition resources
'resources' => array(
...
),
);
The above acl configuration allowed users to define roles and module resources, let's take a look at roles definition first.
- The
roles
field tells application the array is used to add roles to application, in the four case - the
roleName
,admin
,staff
andmanager
are the role name. And thetitle
field indicate the role tile.
Note: The difference between role name and role title is that: role name is used to distinguish different roles, so it must be unique; and the role title can be the same.
-
section
field - this value is used to decide which section a role is belonged to. It can beadmin
,front
, and it can be ignored if the role is in front section. Refer to Case 1. -
parents
field - this value indicates the inherited relationship between different roles. Its parents are passed by an array, if the array contains only one data, it called single inheritance, or else, called multi-inheritance. Refer to Case 2, 3, 4.
Note: In Pi, a child role will inherit the allow
permission of its parent roles, which is said that if a parent allow a resource, the child will can not deny the resource in split of child choose the deny permission.
Definition resources
What is a resource, in Pi, a resources can be a page (it also known as controller/action), or a string.
The following codes is the resources
part of the acl.php
:
'resources' => array(
// Front resources
'front' => array(
'category' => array(
'module' => 'system',
'title' => __('Category'),
'parent' => 'parentCategory',
'access' => array(
'guest' => 0,
'member' => 1,
),
'privileges' => array(
'read' => array(
'title' => 'Read articles',
),
'post' => array(
'title' => 'Post articles',
'access' => array(
'guest' => 0,
),
),
'delete' => array(
'title' => 'Post articles',
'access' => array(
'guest' => 0,
'member' => 0,
),
),
),
),
...
),
'admin' => array(
...
),
),
The code above will insert a system
type resource into the acl_resource
table.
In the array, the front
and admin
fields indicate the resource section. And the category
field indicates the resource name.
-
module
field - indicates the resource module, it can be ignored, therefore the current module name will be used. -
title
field - resource title. -
parent
field - this field indicates the current resource's parent, it will insert current resource as a child of its parent resource. The value of this field can be string or array.The value must be exist resource name if it is string:
'parent' => 'categoryName',
The value can contain resource information if it is an array:
'parent' => array( 'section' => 'admin', 'module' => 'system', ),
-
access
field - this field defines the rules between roles and resources, theguest
,member
is the role name, and the value 0 and 1 define whether the role has permission to access this resource, it will be allowed if this value is set to 1. -
privileges
field - NOT ACHIEVE YET!
Note: actually, the access
field and privileges
can not define at the same time in the same resource.
config/page.php
The page.php
configuration file is used to add pages and page
type resources of a module. It will define the page's controller and action, and its parent resource user defined in the acl.php
.
return array(
// front pages
'front' => array(
...
),
'admin' => array(
// Case 1
array(
'title' => __('All articles'),
'module' => 'article',
'controller' => 'article',
'action' => 'published',
'cache_ttl' => 60,
'cache_level' => 'role',
'block' => 0,
'permission' => array(
'access' => array(
'manager' => 1,
'staff' => 0,
),
),
),
// Case 2
array(
'controller' => 'dashboard',
'permission' => array(
'parent' => 'category',
),
),
),
// Exception of admin pages to skip ACL check
'exception' => array(
array(
'controller' => 'ajax',
),
array(
'controller' => 'upload',
'action' => 'upload',
),
),
);
In the codes, we introduce two cases, the first one define a page with cache and permissions, and the second one define a page and the permission of which is defined in acl.php
.
The declare of the field can be known in the module configuration section of this document.
If user want to define a page resource, case 2 is recommended, in the array:
-
controller
field - indicates the module controller. -
parent
field - indicates the parent resource defined in theacl.php
and its value is the resource name.
Some controller or action need to skip acl check, then we can use exception
field to realize it.
So far, we have defined all the resources, but we have extra thing to do to make it more perfect.
Make navigation hide the denied resource
In the navigation.php
configuration, we need to add extra code to help application hide or display menu according to the permission.
config/navigation.php
return array(
...
'admin' => array(
'article' => array(
...
'resource' => array(
'resource' => 'article',
),
),
),
);
In the code, we add a resource
array, and assign the resource name article
to the resource field. Then the application will check whether current user have permission to access the resource.
Add installing configuration
The last step is to tell the application that we have a acl
and page
configuration to install, this will be achieve by adding fields in module.php
.
config/module.php
return array(
...
'acl' => 'acl.php',
'page' => 'page.php',
);
Note: the acl.php
must be defined before page.php
, or else permission will not take effect after installs.
Pi\Acl\Acl
class is used to manage authentication, it achieve tasks such as:
- Loading user roles;
- Getting resources;
- Adding authentication rules;
- Checking whether a role has permission to access resources.
Methods provided by this class are list as follows:
RowGateway getModel(string $modelName);
Acl setSection(string $section);
string getSection();
Acl setDefault(bool $default);
bool getDefault();
Acl setModule(string $module);
string getModule();
Acl setRole(string $role);
string getRole();
bool addRule(bool|int $allowed, string $role, string $section, string $module, string|int $resource, string $privilege = null);
bool removeRule(string $role, string $section, string $module, string|int $resource, $string $privilege = null);
bool setRule(bool|int $allowed, string $role, string $section, string $module, string|int $resource, string $privilege);
bool isAllowed(string $role, string|array|object $resource, string $privilege = null);
bool checkAccess(string|array|object $resource, string $privilege = null);
array getResources(array|Where $where = null, bool $allowed = true);
array loadRoles(string $role = null);
array loadResources(string|array|Node $resource);
-
Construction
The construction of
Acl
needs two parameters.Parameters
$section: set the resource section, such as:
front
,admin
.$default: set the default permission, when a rule is not specified.
Examples
$aclHandler = new \Pi\Acl\Acl; $aclHandler = new \Pi\Acl\Acl('admin'); $aclHandler = new \Pi\Acl\Acl('admin', true);
-
getModel
Gets a acl model and set section/module if applicable. That is said, users should set section and module before calling
getModel
method if he/she when to set section and module.Parameters
$modelName: acl model name, can be
edge
,inherit
,privilege
,resource
,role
andrule
.Examples
$model = $aclHandler->getModel('role'); $model->getAncestors('manager');
-
setSection($section) and getSection()
Resources section operation methods, used to set section for resources and get current application section.
Parameters
$section: section name, can be
admin
andfront
.Examples
echo $aclHandler->setSection('admin')->getSection();
Output:
'admin'
-
setDefault($default) and getDefault()
Default permission operation.
Parameters
$default: default permission value.
Examples
echo $aclHandler->setDefault(true)->getDefault();
Output:
true
-
setModule($module) and getModule()
Setting resource module and getting current resource module.
Parameters
$module: module name.
Examples
echo $aclHandler->setModule('demo')->getModule();
Output:
'demo'
-
setRole($role) and getRole()
Role operation, the
getRole
method will load from current authenticated user if role is not set.Parameters
$role: role name.
Examples
Suppose current authentication user is
admin
:// Set current role $aclHandler->setRole('manager'); echo $aclHandler->getRole(); // Not set current role echo $aclHandler->getRole();
Output:
'manager' 'admin'
-
addRule()
This method is used to add a rule to database for later use, this method will add a new record into database whatever it is exists.
Parameters
$allowed: whether to allow role to access resources, indicate allowed if set to true.
$role: role name.
$section: resource section.
$module: the name of module resources belong to.
$resource: resource name.
$privilege: resource privilege, can be ignored.
Examples
$aclHandler->setRule(true, 'manager', 'admin', 'demo', $resourceName);
-
removeRule
Remove a exist rule from database.
Parameters
$role: role name.
$section: resource section.
$module: the name of module resources belong to.
$resource: resource name.
$privilege: resource privilege, can be ignored.
Examples
$aclHandler->removeRule('manager', 'admin', 'demo', $resourceName);
-
setRule
This method is also used to add rule, but the difference is that it will update the record if the data is exists.
Parameters
$allowed: whether to allow role to access resources, indicate allowed if set to true.
$role: role name.
$section: resource section.
$module: the name of module resources belong to.
$resource: resource name.
$privilege: resource privilege, can be ignored.
Examples
$aclHandler->setRule(true, 'manager', 'admin', 'demo', $resourceName);
-
isAllowed
This method is used to check access to a resource by given role parameter. It will return true if the resource is allowed to access.
Parameters
$role: role name.
$resource: this parameter can be a string indicate the resource name, or an array contains resource data. The resource type can refer to
loadResources
method.$privilege: resource privilege, can be ignored.
Examples
$aclHandler->isAllowed('manager', array( 'module' => 'system', 'controller' => 'config', )); $aclHandler->isAllowed('manager', 'config');
-
checkAccess
This method is used to access a resource privilege for a given role, if the role is not set, current authentication role will be used.
Parameters
$resource: resource name, as same as
isAllowed
method.$privilege: privilege name.
// use given role $aclHandler->setRole('manager')->checkAccess(array( 'name' => 'config', )); // use current role $aclHandler->checkAccess(5);
-
getResources
This method is used to get resources to which a group of roles by given conditions.
Parameters
$where: the given conditions.
$allowed: whether to choose allowed resources.
Examples
$aclHandler->getResources(array( 'resource' => 'system', 'module' => 'system', ), false);
-
loadRoles
This method is used to load ancestors of a role from database.
Parameters
$role: role name.
Examples
$aclHandler->loadRoles('manager');
Output:
array( 0 => 'admin', 1 => 'staff', )
-
loadResources
This method is used to load ancestors of a resource from database.
Parameters
$resource
The resource parameter can be string which is the resource name or id, or an array contain resource data.
Examples
-
Case 1: load a page resource (which describes by controller/action) by array, it will return two resource ids which is a system resource id and a page resource id, and the page resource is the child of system resource.
Note: the
module
field is needed.$resource = array( 'module' => 'system', 'controller' => 'config', ); // Alternate $resource = array( 'type' => 'system', // this field can be ignored 'name' => 'config', ); $aclHandler->loadResources($resource);
Output:
array( 0 => 5, // system resource id 1 => 26, // page resource id )
-
Case 2: load only a system resource, note that do not set 'module' field.
$resource = array( 'type' => 'system', // this field can be ignored 'name' => 'config', ); $aclHandler->loadResources($resource);
Output:
array( 0 => 5, // system resource id )
-
Case 3: load a resource by digit
$aclHandler->loadResources('3'); $aclHandler->loadResources(5);
Output:
array( 0 => 3, )
array( 0 => 4, )
-
Case 4: load a resource by string name
$aclHandler->loadResources('config');
Output:
array( 0 => 4, )
Now we will introduce how to create module authentication by a case, this case will achieve the following tasks:
- Adding a module role and its child to application;
- Adding a page resource (also a navigation menu) and a system resource by configuration;
- Allowing the created roles to access the resource;
- Enabling show the view menu when the user has authentication to access the resource;
- Adding a page resource and a system resource in module;
- Checking whether the role has authentication to access the resources.
Supposing our module named article
.
TASK 1, TASK 2 and TASK 3
module/article/config/acl.php
return array(
// Creating roles
'roles' => array(
// Admin role inherit from manager for article module
'contributor' => array(
'title' => __('Contributor'),
'section' => 'admin',
'parents' => array('staff'),
),
// Temporary editor inherit from contributor
'temporary' => array(
'title' => __('Temporary editor'),
'section' => 'admin',
'parents' => array('contributor'),
),
),
// Creating resources
'resources' => array(
'admin' => array(
// Creating a system resource
'editor' => array(
'module' => 'article',
'title' => __('Editor'),
'access' => array(
'temporary' => 1,
),
),
// Page resource, defined in page.php
// This is also the navigation menu of article module
'article' => array(
'module' => 'article',
'title' => __('All article management'),
'access' => array(
'contributor' => 1,
),
),
),
),
);
module/article/config/page.php
return array(
'admin' => array(
// Indicating the article resource is a page resource
array(
'controller' => 'article',
'permission' => array(
'parent' => 'article',
),
),
),
// Exception of admin pages to skip ACL check
'exception' => array(
array(
'controller' => 'ajax',
),
),
);
In the above case, we define two role and two resources, and the contributor
role is defined as child role of system role staff
, by defining in acl.php
to indicate the article
resource is a page resource, then the access
field is used to tell the application contributor
role is allow to access the article
resource.
In module, we may have some ajax action, this action is always allowed to access, so we use exception
field to tell the application this action do not need acl check.
TASK 4
module/article/config/navigation.php
return array(
'item' => array(
'admin' => array(
'article' => array(
'label' => 'All articles',
'route' => 'admin',
'controller' => 'article',
'resource' => array(
'resource' => 'article',
),
'pages' => array(
...
),
),
),
),
);
In this case, we define a resource
field, and assign resource name article
to it to tell the application check the authentication of this resource, and decide whether to hidden the navigation menu.
Add configuration file to the module.php
module/article/config/module.php
return array(
...
'acl' => 'acl.php',
'page' => 'page.php',
);
TASK 5 and TASK 6
module/article/src/Controller/Admin/IndexController.php
...
use Pi\Acl\Acl;
class IndexController extends ActionController
{
public function indexAction()
{
...
$acl = new Acl('admin');
// Allow system role to access system resource
$acl->setRule(true, 'contributor', 'admin', $this->getModule(), 'edit');
// Allow system role to access page resource
$acl->setRule(true, 'contributor', 'admin', $this->getModule(), array(
'module' => $this->getModule(),
'controller' => 'index',
'action' => 'perm'
));
// Allow dynmic role to access system resource
$acl->setRule(true, 'editor', 'admin', $this->getModule(), 'delete');
...
}
public function permAction()
{
...
$acl = new Acl('admin');
$acl->setModule($this->getModule());
// Checking page resource
if ($acl->checkAccess(array(
'module' => $this->getModule(),
'controller' => 'index',
'action' => 'perm'
))) {
return $this->jumpToDenied('__denied__');
}
// Checking system resource
$rules['edit'] = $acl->checkAccess('edit');
// Checking resource for dynmic role
$rules['delete'] = $acl->->isAllowed('editor', 'delete');
$this->view()->assign('rules', $rules);
...
}
}
module/article/template/admin/index-perm.phtml
<?php if ($rule['edit']) { ?>
<div><a href="#"><?php echo __('Edit') ?></a></div>
<?php } ?>
<?php if ($rule['delete']) { ?>
<div><a href="#"><?php echo __('Delete') ?></a></div>
<?php } ?>