This document is for a version of CakePHP that is no longer supported. Please upgrade to a newer release!
As mentioned before, there is no pre-built way to input all of our controllers and actions into the Acl. However, we all hate doing repetitive things like typing in what could be hundreds of actions in a large application.
For this purpose exists a very handy plugin available on GitHub, called AclExtras which can be downloaded in The GitHub Downloads page. We’re going to briefly describe how to use it to generate all our ACO’s
First grab a copy of the plugin and unzipped or clone it using git into app/Plugin/AclExtras. Then activate the plugin in your app/Config/boostrap.php file as shown below:
//app/Config/boostrap.php
// ...
CakePlugin::load('AclExtras');
Finally execute the following command in the CakePHP console:
./Console/cake AclExtras.AclExtras aco_sync
You can get a complete guide for all available commands like this:
./Console/cake AclExtras.AclExtras -h
./Console/cake AclExtras.AclExtras aco_sync -h
Once populated your acos table proceed to create your application permissions.
Creating permissions much like creating ACO’s has no magic solution, nor will I be providing one. To allow ARO’s access to ACO’s from the shell interface use the AclShell. For more information on how to use it consult the AclShell help which can be accessed by running:
./Console/cake acl --help
Note: * needs to be quoted (’*’)
In order to allow with the AclComponent
we would use the
following code syntax in a custom method:
$this->Acl->allow($aroAlias, $acoAlias);
We are going to add in a few allow/deny statements now. Add the
following to a temporary function in your UsersController
and
visit the address in your browser to run them (e.g.
http://localhost/cake/app/users/initdb). If you do a
SELECT * FROM aros_acos
you should see a whole pile of 1’s and
-1’s. Once you’ve confirmed your permissions are set, remove the
function:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('initDB'); // We can remove this line after we're finished
}
public function initDB() {
$group = $this->User->Group;
// Allow admins to everything
$group->id = 1;
$this->Acl->allow($group, 'controllers');
// allow managers to posts and widgets
$group->id = 2;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Posts');
$this->Acl->allow($group, 'controllers/Widgets');
// allow users to only add and edit on posts and widgets
$group->id = 3;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Posts/add');
$this->Acl->allow($group, 'controllers/Posts/edit');
$this->Acl->allow($group, 'controllers/Widgets/add');
$this->Acl->allow($group, 'controllers/Widgets/edit');
// allow basic users to log out
$this->Acl->allow($group, 'controllers/users/logout');
// we add an exit to avoid an ugly "missing views" error message
echo "all done";
exit;
}
We now have set up some basic access rules. We’ve allowed administrators to everything. Managers can access everything in posts and widgets. While users can only access add and edit in posts & widgets.
We had to get a reference of a Group
model and modify its id to
be able to specify the ARO we wanted, this is due to how
AclBehavior
works. AclBehavior
does not set the alias field
in the aros
table so we must use an object reference or an
array to reference the ARO we want.
You may have noticed that I deliberately left out index and view
from my Acl permissions. We are going to make view and index public
actions in PostsController
and WidgetsController
. This
allows non-authorized users to view these pages, making them public
pages. However, at any time you can remove these actions from
AuthComponent::allowedActions
and the permissions for view and
edit will revert to those in the Acl.
Now we want to take out the references to Auth->allowedActions
in your users and groups controllers. Then add the following to
your posts and widgets controllers:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('index', 'view');
}
This removes the ‘off switches’ we put in earlier on the users and
groups controllers, and gives public access on the index and view
actions in posts and widgets controllers. In
AppController::beforeFilter()
add the following:
$this->Auth->allow('display');
This makes the ‘display’ action public. This will keep our PagesController::display() public. This is important as often the default routing has this action as the home page for your application.
Our application is now under access control, and any attempt to
view non-public pages will redirect you to the login page. However,
we will need to create a login view before anyone can login. Add
the following to app/View/Users/login.ctp
if you haven’t done
so already:
<h2>Login</h2>
<?php
echo $this->Form->create('User', array(
'url' => array(
'controller' => 'users',
'action' => 'login'
)
));
echo $this->Form->input('User.username');
echo $this->Form->input('User.password');
echo $this->Form->end('Login');
If a user is already logged in, redirect him by adding this to your UsersController:
public function login() {
if ($this->Session->read('Auth.User')) {
$this->Session->setFlash('You are logged in!');
return $this->redirect('/');
}
}
You should now be able to login and everything should work
auto-magically. When access is denied Auth messages will be
displayed if you added the echo $this->Session->flash('auth')
Now onto the logout. Earlier we left this function blank, now is
the time to fill it. In UsersController::logout()
add the
following:
$this->Session->setFlash('Good-Bye');
$this->redirect($this->Auth->logout());
This sets a Session flash message and logs out the User using Auth’s logout method. Auth’s logout method basically deletes the Auth Session Key and returns a URL that can be used in a redirect. If there is other session data that needs to be deleted as well add that code here.
You should now have an application controlled by Auth and Acl. Users permissions are set at the group level, but you can set them by user at the same time. You can also set permissions on a global and per-controller and per-action basis. Furthermore, you have a reusable block of code to easily expand your ACO table as your app grows.