The cake built in CRUD auth is way too powerful and way too slow and memory consuming.
In 99% of all cases there is no need for that.
If you just want to have some basic control over the access to specific actions, you need sth else.
Here it comes.
Preparations
I assume you already got the AuthComponent included in the $components array of your AppController.
You probably also excluded all public views with sth like
{code type=php}
$this->Auth->allow('contact_form'); # in beforeFilter() of the specific controllers
{/code}
This here (in the contact controller) makes Auth skip this action completely. The action will be accessable to everybody right away.
You probably got a Role model (User belongsTo Role / User hasAndBelongsToMany Role) attached to the User.
If you don't want this, use Configure to store your keys like so:
{code type=php}
$config['Role'] = array(
'superadmin' => 1,
'admin' => 2,
'moderator' => 3,
'helper' => 4,
'user' => 5,
);
{/code}
You should at least have the user and admin role for it to make sense.
You should also have some kind of Authentication in your AppController:
{code type=php}
$this->Auth->authenticate = array('Form')); # uses username and password for login
{/code}
So far so good. You can login/logout and once you are logged in browse all non-public pages.
Even admin pages, of course. Thats where the TinyAuth class comes in.
TinyAuth
The code can be found at github.
First of all include it in your beforeFilter() method of the AppController:
{code type=php}
$this->Auth->authorize = array('Tools.Tiny');
{/code}
If you don't place this code into your "Tools" plugin, make sure to remove the Tools. prefix then.
Now create a file in /Config/ called acl.ini like so:
{code type=ini}
[Tools.Countries]
* = superadmin ; this is a comment
[Account]
edit,change_pw = *
[Activities]
admin_index,admin_edit,admin_add,admin_delete = admin,superadmin
index = *
[Users]
index,search = user
* = moderator,admin
{/code}
The format is normal PHP INI style. I already included all kind of examples. * is a placeholder for "any".
The plugin prefix for controllers is not necessary as of now (maybe for Cake3 where the same controller name is allowed multiple times due to PHP5.3 namespaces).
Comments in ini files start with ";".
Explanations:
- Superadmin can access all Countries actions
- Account actions are accessable by all roles (and therefore logged in users)
- Activities can be modified by all admins and listed by all everyone
- Users can search and list other others, but only moderators and admins have access to all other ations
That's it. Really easy, isn't it?
Some details
TinyAuth expects a Session Auth User like so:
{code type=php}
Auth.User.id
Auth.User.role_id (belongsTo - role key directly in the users table)
{/code}
or so:
{code type=php}
Auth.User.id
Auth.User.Role (hasAndBelongsToMany - multi role array containing all role keys)
{/code}
As you can see it can manage both single and multile role setup.
That's sth the core one lacks, as well.
The current configuration is cached in the persistent folder by default. In development mode (debug > 0) it will be regenerated all the time, though. So remember that you have to manually clear your cache in productive mode for changes to take effect!
Quicktips
If you have a cleanly separated user/admin interface there is a way to allow all user actions to users right away;
{code type=php}
$this->Auth->authorize = array('Tools.Tiny'=>array('allowUser'=>true));
{/code}
Only for admin views the authorization is required then.
If you got a "superadmin" role and want it to access everything automatically, do this in the beforeFilter method of your AppController:
{code type=php}
$userRoles = $this->Session->read('Auth.User.Role');
if ($userRoles && in_array(Configure::read('Role.superadmin'), $userRoles)) {
# Skip auth for this user entirely
$this->Auth->allow('*');
}
{/code}
UPDATE 2012-01-10
The auth model can now be anything you like. It doesn't have to be `Role` or `role_id`.
The new cake2.x uses "groups" per default.
You can easily adjust that now by passing `aclModel` => 'Group' or `aclKey` => 'group_id' to the Tiny class, for instance.
The cake built in CRUD auth is way too powerful and way too slow and memory consuming.
In 99% of all cases there is no need for that.
If you just want to have some basic control over the access to specific actions, you need sth else.
Here it comes.
Preparations
I assume you already got the AuthComponent included in the $components array of your AppController.
You probably also excluded all public views with sth like
$this->Auth->allow('contact_form'); # in beforeFilter() of the specific controllers
This here (in the contact controller) makes Auth skip this action completely. The action will be accessable to everybody right away.
You probably got a Role model (User belongsTo Role / User hasAndBelongsToMany Role) attached to the User.
If you don’t want this, use Configure to store your keys like so:
$config['Role'] = array(
'superadmin' => 1,
'admin' => 2,
'moderator' => 3,
'helper' => 4,
'user' => 5,
);
You should at least have the
user and
admin role for it to make sense.
You should also have some kind of Authentication in your AppController:
$this->Auth->authenticate = array('Form')); # uses username and password for login
So far so good. You can login/logout and once you are logged in browse all non-public pages.
Even admin pages, of course. Thats where the TinyAuth class comes in.
TinyAuth
The code can be found at github.
First of all include it in your beforeFilter() method of the AppController:
$this->Auth->authorize = array('Tools.Tiny');
If you don’t place this code into your “Tools” plugin, make sure to remove the Tools. prefix then.
Now create a file in /Config/ called acl.ini like so:
[Tools.Countries]
* = superadmin ; this is a comment
[Account]
edit,change_pw = *
[Activities]
admin_index,admin_edit,admin_add,admin_delete = admin,superadmin
index = *
[Users]
index,search = user
* = moderator,admin
The format is normal PHP INI style. I already included all kind of examples. * is a placeholder for “any”.
The plugin prefix for controllers is not necessary as of now (maybe for Cake3 where the same controller name is allowed multiple times due to PHP5.3 namespaces).
Comments in ini files start with “;”.
Explanations:
- Superadmin can access all Countries actions
- Account actions are accessable by all roles (and therefore logged in users)
- Activities can be modified by all admins and listed by all everyone
- Users can search and list other others, but only moderators and admins have access to all other ations
That’s it. Really easy, isn’t it?
Some details
TinyAuth expects a Session Auth User like so:
Auth.User.id
Auth.User.role_id (belongsTo - role key directly in the users table)
or so:
Auth.User.id
Auth.User.Role (hasAndBelongsToMany - multi role array containing all role keys)
As you can see
it can manage both single and multile role setup.
That’s sth the core one lacks, as well.
The current configuration is cached in the persistent folder by default. In development mode (debug > 0) it will be regenerated all the time, though. So remember that you have to manually clear your cache in productive mode for changes to take effect!
Quicktips
If you have a cleanly separated user/admin interface there is a way to allow all user actions to users right away;
$this->Auth->authorize = array('Tools.Tiny'=>array('allowUser'=>true));
Only for admin views the authorization is required then.
If you got a “superadmin” role and want it to access everything automatically, do this in the beforeFilter method of your AppController:
$userRoles = $this->Session->read('Auth.User.Role');
if ($userRoles && in_array(Configure::read('Role.superadmin'), $userRoles)) {
# Skip auth for this user entirely
$this->Auth->allow('*');
}
UPDATE 2012-01-10
The auth model can now be anything you like. It doesn’t have to be Role or role_id.
The new cake2.x uses “groups” per default.
You can easily adjust that now by passing aclModel => 'Group' or aclKey => 'group_id' to the Tiny class, for instance.
Matt
January 2, 2012 at 17:19
This is really great and something sorely missing from the core Cake distro. My only suggestion is that you do not assume the reader has so much in place already. I suspect most people who are looking for something like this are doing so because they could not get the complicated aro/aco stuff working easily and would love a step-by-step of getting tinyAuth up and running.
Also, the examples and tutorials in the cookbook 2.0 have users/groups tables instead of users/roles. You might want to specify the schema your plugin expects since it is different from those.
Matt
January 2, 2012 at 17:24
There is one thing I am having trouble with. When an action is not allowed, the site just hangs and returns nothing. Any suggestions on how to have it return some kind of page, or return back to where it came from with a flash error message?
Here is what I have in my AppController beforeFilter()
Mark
January 2, 2012 at 22:40
Good points. I will have to refine it.
Ok, so roles in 1.3 have changed to groups in 2.0 then? But they still seem to be 1:N only (multiple roles/groups per user not possible). The documentation doesn't reveal much.
About your problem:
Your Auth component is responsable for that. The Tiny (or any other Auth for that matter) can only return true/false or the right to access this page. It used to redirect to /. But I opened a ticket (http://cakephp.lighthouseapp.com/projects/42648/tickets/2390-auth-component-should-not-redirect-to-index-if-loginredirect-is-set) because it doesnt make any sense if you are a logged in user (you would want to be redirected to $this->Auth->loginRedirect).
And thats exactly what the core Auth component does:
Matt
January 3, 2012 at 04:07
OK, I think I figured out part of the hanging issue. When a page is not authorized, it is trying to redirect to /, but that is also not authorized. I have not figured out how to specify / in the acl.ini file. It is probably obvious, but I'm still a cake newbie.
Mark
January 3, 2012 at 11:30
Well, that is a misconfiguration
Your homepage (/) should always be public. Use $this->Auth->allow() in your controller for this action.
Forbin
January 7, 2012 at 15:37
Does this work in 1.3?
jetwes
January 9, 2012 at 12:24
I always get a failure after login:
Mein Model ist so definiert:
Any Hints?
Good work – keep on!
Mark
January 9, 2012 at 12:32
You need to make sure the session contains the role information after logging the user in:
HABTM (multiple roles per user):
User.Role.id1,id2,…,idx,
BT (one role per user):
User.role_id
jetwes
January 9, 2012 at 17:32
got it, thanks again for the quick support! Is there a easy way to build a dynamic menu with the acls? (It depends on the role if a user can see the menu item)
Keep up the good work!
Mark
January 11, 2012 at 01:54
I updated the class to allow other parent model relations besides "User<–>Role". It should be closer to the cookbook now, where they use "Groups".
@jetwes
There sure is a way to do that. I would like to use sth like that very much, as well.
Basically we would need a helper to display certain "navigation" blocks and hide the ones you don't have access to. With caching this should be not too resource-eating…
Nitish
January 24, 2012 at 11:31
Hey Mark,
Thanks for the good work.
I am saying its good, because it looks like that & you won't claim it being the fastest & easiest..
I am a newbie in Cake, I have setup cake2.0 & I tried to follow your instructions but like "Matt" said, you can still make the tutorial more clear & to the point & step by step. I got confused at points like -
"If you don’t want this, use Configure to store your keys like so:"
I took some time to figure out that I need to do this in bootstrap file using Configure::write.. I am still not sure if this is the right way..
Basically, steps starting from we downloading cake & till the point where we are ready with a basic setup will be something that will help this a lot
Thanks & Hoping you help me out
Nitish
January 24, 2012 at 11:45
Actually .. Something like the book tutorial – http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html, will be really good