views:

366

answers:

1

Struggling with a decision on how best to handle Client-level authentication with the following model hierarchy:

Client -> Store -> Product (Staff, EquipmentItem, etc.)

...where Client hasMany Stores, Store hasMany Products(hasMany Staff, hasMany EquipmentItem, etc.)

I've set up a HABTM relationship between User and Client, which is straightforward and accessible through the Auth session or a static method on the User model if necessary (see afterFind description below).

Right now, I'm waffling between evaluating the results in each model's afterFind callback, checking for relationship to Client based on the model I'm querying against the Clients that the current User is a member of. i.e. if the current model is Client, check the id; if the current model is a Store, check Store.clientid, and finally if Product, get parent Store from Item.storeid and check Store.clientid accordingly.

However, to keep in line with proper MVC, I return true or false from the afterFind, and then have to check the return from the calling action -- this is ok, but I have no way I can think of to determine if the Model->find (or Model->read, etc.) is returning false because of invalid id in the find or because of Client permissions in the afterFind; it also means I'd have to modify every action as well.

The other method I've been playing with is to evaluate the request in app_controller.beforeFilter and by breaking down the request into controller/action/id, I can then query the appropriate model(s) and eval the fields against the Auth.User.clients array to determine whether User has access to the requested Client. This seems ok, but doesn't leave me any way (afaik) to handle /controller/index -- it seems logical that the index results would reflect Client membership.

Flaws in both include a lengthy list of conditional "rules" I need to break down to determine where the current model/action/id is in the context of the client. All in all, both feel a little brittle and convoluted to me.

Is there a 3rd option I'm not looking at?

A: 

This sounds like a job for Cake ACL. It is a bit of a learning curve, but once you figure it out, this method is very powerful and flexible.

Cake's ACLs (Access Control Lists) allow you to match users to controllers down to the CRUD (Create Read Update Delete) level. Why use it?

1) The code is already there for you to use. The AuthComponent already has it built in. 2) It is powerful and integrated to allow you to control permissions every action in your site. 3) You will be able to find help from other cake developers who have already used it. 4) Once you get it setup the first time, it will be much easier and faster to implement full site permissions on any other application.

Here are a few links:

http://bakery.cakephp.org/articles/view/how-to-use-acl-in-1-2-x http://book.cakephp.org/view/171/Access-Control-Lists http://blog.jails.fr/cakephp/index.php?post/2007/08/15/AuthComponent-and-ACL

Or you could just google for CakePHP ACL

Dooltaz
I've looked into ACL, and from what I've read, it doesn't work (and it's not recommended) for row or model based authentication, which is what I'm after.
gravyface
I'm not sure of the advantage of permissions at the model level. However, have you considered using UUID's and creating a single permissions HABTM table between all of your tables. Then you can use custom model binding for checking permissions. In your beforeFind just put a bindModel('permissions'). Then managing permissions would have custom bindModels, etc.
Dooltaz