←How To Play Hearts With Only Two Players| Tweet Design→
View full index of ACL Tutorial Articles
The most common initial question people have when learning about the CakePHP ACL component is: “how do I let a user edit her own profile BUT only that one profile”?
The short story is that the CakePHP ACL component does not, nor is meant to, automatically provide this kind of record level protection.
If you want to add protection to individual articles, you must do this on your own.
Most commonly, we want to:
Assume that we have a UsersController with the standard actions: index, view, edit, add.
We want the typical users to be able to view and edit their own records. The easiest way to restrict this, is to create the following function in the UsersController:
function checkUsersOwnRecord($recordId = null)
{
if( $this->Auth->user('id') == $recordId ){
return TRUE;
} else {
return FALSE;
}
}
Now, in the edit and view functions, we can make a call to the checkUsersOwnRecord() function using the record id requested in the URL. If the function returns TRUE, then we can continue displaying or processing the view logic which will let the user edit only her own record.
In order to allow this on the ACL side of things we have to set up the following:
For this last point, if you are using ‘actions’ mode, then you will need to grant ALL users access to the UsersController::edit() and UsersController:view() actions.
If you are using crud mode, you will need to grant ALL USERS “UPDATE” and “READ” access to the UsersController.
The last sentence highlights one of the main pitfalls of working with the crud mode.
If we grant all users READ access to the UsersController, then all users will also have access to the UsersController::index() action, and this might not be desirable, for we might not want ALL users to be able to view a complete listing of users in the system.
There is a solution to this, but first, let’s get back to the initially stated requirement that we want to give administrators the ability to edit all user records.
One really straightforward way to allow an admin access to all records would be to create some sort of exception in our checkUsersOwnRecord() function. Maybe we could check to see if the logged in user is part of the admin group, and if they are, then let them edit the record.
But this is going to lead to problems down the road if we start adding different levels of administration. In general, we don’t want to add this kind of hard-coded ACL check into our Controller code.
The right solution under ‘actions’ mode is to create a new action in your UsersController called admin_edit.
This new action would provide edit access to all users. There would be a corresponding ACO node and anyone who was allowed to have full access to all user records can be granted access to this ACO node.
Your ACO tree might look like this:
Users
---- index [maybe only admins get access to this]
---- edit [this is the action restricted with a function]
---- admin_edit [this allows full access]
The problem is slightly more difficult in crud mode. By granting a user access to “READ” rights, you let that user have access to all actions normally associated with READ. Also, by granting a user access to “UPDATE” rights, you are going to let that user have access to all actions associated with UPDATE.
One slightly ugly solution would be to remap the UsersController actions in the beforeFilter() function.
$this->Auth->actionMap['index'] = 'delete';
$this->Auth->actionMap['view'] = 'read';
$this->Auth->actionMap['edit'] = 'read';
$this->Auth->actionMap['admin_edit'] = 'delete';
$this->Auth->actionMap['delete'] = 'delete';
Here, we would create a new function called admin_edit which would allow edit access to any user record. The index of these records would be viewable with the index view. Access rights would be handled by granting admins “DELETE” access to UsersController().
The solution I prefer, however, is to create a brand new controller called, UserprofilesController. This new controller will have the standard actions and views.
We can associate it with the User model by putting the following at the top of the class:
public $uses = array('User');
Now you can grant users various levels of access to this controller and in doing so control who gets access to the various levels of user administration.
Meanwhile, on the UsersController dumb down your index function, so that it doesn’t return anything to the user. And you might as well just remove the delete() function entirely. To keep things simple, just grant everyone READ And UPDATE access to UsersController, and leave it at that.
Our ACO tree will look like this:
Users
Userprofiles
All users will have READ and UPDATE access to Users, but only admins will have access to Userprofiles.
I’m not really sure which is the better option, but the issue of record level access control might be the biggest reason why you might want to go with ‘actions’ mode or ‘crud’ mode.
Under ‘actions’ mode, you will need to create special admin_ actions for each controller which is going to have record level access control. This might make your ACO node tree bigger than it needs to be if, for each controller, you have to also have an admin_index, admin_edit, and admin_create function.
Under ‘crud’ mode, you will wind up with more controllers. But those controllers will contain fewer actions. But overall, you will have fewer nodes in your ACO tree.
Sunday March 1, 2009
I'm Aran Johnson and I make websites.
I primarily use: PHP, MySQL, SubVersion, CakePHP, TextPattern, Cream Text Editor, and Addi Turbo Needles
Oakland Parking Violations and Fines
CakePHP ACL and Auth: Record Level Protection
How To Play Hearts With Only Two Players
CakePHP ACL and Auth: Record Level Protection
CakePHP ACL and Auth: Sample Website
CakePHP ACL and Auth Tutorial: Database Setup
CakePHP ACL Tutorial: Introduction
CakePHP ACL Tutorial: Usage With Auth Component
CakePHP ACL Tutorial: Initial Setup
CakePHP ACL Tutorial: Auth Component Example
CakePHP ACL Tutorial: How To Check Access
Cake PHP ACL Tutorial: The Database Tables