This article is part of the CakeDC Advent Calendar 2024 (December 22nd 2024)
Authorization can become a complex topic. If you go over the options described in the CakePHP Book, https://book.cakephp.org/authorization/3/en/index.html and the specific tutorial https://book.cakephp.org/5/en/tutorials-and-examples/cms/authorization.html, you'll see that there are options to define the authorization in a very flexible way.
In CakePHP, the Authorization Plugin will allow you to define subjects of authorization, entities that want to get access to one of these subjects, and rules to determine if the entities can have access to a given subject.
Many CakePHP applications coming from versions 1,2,3 don't require a lot of flexibility because they define:
- Subject: a plugin/prefix/Controller/action, like a "url" in our site, for example: "/admin/users/add"
- Entity: a logged in user, or a guest user who is not logged in yet. Usually we'll group the users in a role, to allow assigning permissions per role
- Rule: a function, returning true or false
In these cases, we can build an authorization table, like
URL Role CanAccess?
/admin/users/index admins yes
/admin/users/index users no
...
To apply these concepts in you CakePHP Application, you can use existing plugins like:
But, following our spirit of simplicity, let's imagine you've implemented the CakePHP CMS Tutorial https://book.cakephp.org/5/en/tutorials-and-examples.html.
Or, you can clone the project from here: https://github.com/cakephp/cms-tutorial.
- Clone project
git clone https://github.com/cakephp/cms-tutorial.git
- Create config/app_local.php file with your datasource configuration, for example this one https://gist.github.com/steinkel/c28ffb6dfe36294e6d4e378ad71d564a
- Run migrations
bin/cake migrations migrate
bin/cake server
- Enjoy, visit http://localhost:8765
In this case, to enable url base authentication we would need to change:
-
composer require cakedc/auth
-
Update the AuthorizationService configuration to map the request object with a collection of policies
// src/Application::getAuthorizationService
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
{
$map = new MapResolver();
$map->map(
ServerRequest::class,
new CollectionPolicy([
SuperuserPolicy::class,
new RbacPolicy([
[
'role' => '*',
'controller' => 'Pages',
'action' => 'display',
],
// other rules
// the rules could be stored in a configuration file or database
]),
])
);
$orm = new OrmResolver();
$resolver = new ResolverCollection([
$map,
$orm,
]);
return new AuthorizationService($resolver);
}
- The last piece to this approach would be adding the RequestAuthorizationMiddleware:
// src/Application::middleware
public function middleware($middlewareQueue): \Cake\Http\MiddlewareQueue
{
$middlewareQueue
// ...
->add(new AuthorizationMiddleware($this))
->add(new RequestAuthorizationMiddleware());
How will it work?
For each request to your application, the RequestAuthorizationMiddleware will trigger an authorization check, looking for a Policy in the MapResolver. We'll check first if the user has the column is_superuser
set as true, and if not, we'll use the Rbac to check if the user can access the given URL, using the routing parameters.
The Rbac class provides a lot of flexibility to configure the rules, see https://github.com/CakeDC/auth/blob/8.next-cake5/Docs/Documentation/Rbac.md.
Note: the users
table included in the CMS Tutorial does not include a role
column. If you want to define roles, you would need to add it using a Migration.
Recap
We've used the cms tutorial application from the CakePHP Book to implement a Request Authorization Rbac policy for simple applications looking for a way to determine if a given URL can be accessed by a user role.
This article is part of the CakeDC Advent Calendar 2024 (December 22nd 2024)