Authorization service for Laminas. Span multiple authorization links and access control lists by defining annotations in your controller classes.
Out of the box, Laminas’s authentication module provides interfaces and services
for authenticating users and saving their identities in a session storage.
This module provides an authorization service by transparently redirecting
unauthorized users accessing a certain resource, with the support of defining
multiple authorization links forming an authorization chain.
You can configure the list of controller/method authorization statuses (policies)
by creating annotations on top of your methods or setting it in the configuration.
Install using composer, run
$ composer require alichry/laminas-authorization
Add the modules AliChry\Laminas\AccessControl
andAliChry\Laminas\Authorization
to config/modules.config.php
This module is not concerned with authenticating users, rather, its only intent
is to check the authorization status of the (authenticated) identity. To create
an authorization link, we require:
AuthenticationServiceInterface
:AccessControlListInterface
:IdentityAccessControlList
AnnotatedResourceManager
IdentityInterface
.The fastest path to create a Laminas application with authorization support is
through Doctrine ORM integration. If you’re unfamiliar with Doctrine ORM, please
check the doctrine project website and
doctrine/doctrine-orm-module
IdentityInterface
.hasPermission
and hasRole
, in an ORM environmentDoctrine\Authentication
<?php
# module.config.php
use Laminas\Authentication\AuthenticationService;
return [
// ...
'alichry' => [
'authorization' => [
'chain' => [
'global' => [
'redirect_route' => 'login',
'authentication_service' => AuthenticationService::class,
'access_control_list' => 'identity'
]
]
]
],
// ...
];
The authorization service is now configured, you can define annotations on top of
your methods to indicate authorization policies.
On top of your controller’s method or class docblock, you can define @Authorization
annotations,
indicating:
You can define multiple annotations, each with a different link name.
Additionally, you can omit the link name and it will be treated as the fallback.
Example:
<?php
use AliChry\Laminas\Authorization\Annotation\Authorization;
/**
* Class-level annotations are treated as a fallback. First method annotations
* are consulted, if no relevant method annotations were found then
* class-level annotations are utilized.
*
* Default class policy is to reject unspecified links:
* @Authorization(policy="Reject")
*
* Require valid authentication status for "global" link:
* @Authorization(link="global", policy="Authenticate")
*/
class ApplicationController
{
/**
* Allow this resource to be publicly accessible:
* @Authorization(policy="Allow")
* The above will override class-level annotations, and since the link
* property was omitted, it will apply to all links.
*/
public function indexAction()
{
}
/**
* Allow this resource to be accessible by entities granted the "delete"
* permission under the "global" link:
* @Authorization(link="global", policy="Authorize", permission="delete")
*/
public function deleteAction()
{
}
/**
* No annotations are defined for this method, the class annotations
* will be used as a fallback. This method requires the user to be
* authenticated for the "global" link or the request is rejected for all
* other links.
*/
public function profileAction()
{
}
}
An Authorization Link can infer whether an
(authenticated) identity is authorized to access a controller or a controller’s
action.
This is achieved by relying on AuthenticationService
(for authentication status)
and a AccessControlListInterface
from
alichry/laminas-accesscontrol
that implies the accessibility or authorization level of a controller or a
controller’s method.
Eventually, an Authorization Link can imply whether an (authenticated) identity
is granted access to a certain resource (controller/action) and will return the
result.
An Authorization Chain is built from one or more Authorization Links which the
authorization result is aggregated using a specified binary operator (OR/AND).
While most applications generally utilize only one link, this is primarily
related to the design.
If you are building an administrative end for your application, you may end up
using a different Authentication Service, therefore additional Authorization Link
and ACL. Alternatively, you may use the same Authentication Serivce and assign
each identity with a user or admin role/permission (or the like…)
We perform authorization during the MVC lifecycle and prior dispatching requests for
restful controllers. In Laminas MVC architecture, the target method to call
for an action-based controller is retrievable prior dispatch by listening on
the MVC dispatch event. For restful controllers, however, the target method cannot
be retrieved prior dispatch. We provide
EigenRestfulController as an ad-hoc
solution. Simply extend your controller from EigenRestfulController
instead ofAbstractRestfulController
.
During authorization, whether on the MVC-level or executed by EigenRestfulController
,
we redirect unauthorized requests to a configured route.
See config.md
It would be nice to star this repository. It would help attract more
contributors, and makes me happy to receive a star ! :)