Simple Data Access Control
Posted by Felix Geisendörfer, on Aug 25, 2008 - in PHP & CakePHP » Auth, Acl & Permissions
Hey folks,
this is post #6 of my 30 day challenge.
If your application is like most, then you have some basic permission requirements for your data. A simple scenario is the following. Blog posts can only be edited by their owners and administrators. Same goes for viewing unpublished blog posts. Given that requirement I usually wrote code like this in the past:
-
class PostsController extends Controller{
-
function view($id = null) {
-
$post = $this->Post->findById($post);
-
$ownPost = $post['Post']['user_id'] == User::get('id');
-
}
-
-
function edit($id = null) {
-
$post = $this->Post->findById($post);
-
$ownPost = $post['Post']['user_id'] == User::get('id');
-
}
-
}
Note: See this post about the Assert implementation. If you wonder about the User::get('id') call - that is part of our custom Auth system we hope to publish at some point.
One could argue that the above is not ideally DRY and therefor should be refactored. In the past I probably would have followed that logic. However, these days I'm more often like fuck DRY if a little dupplication here and there makes code easier to read and to maintain (yes, that is very much possible with certain one liners).
Anyway, what I don't like about the above is that I feel the logic for deciding record permissions falls into the Model realm. It simply makes more sense if you think of it as a business requirement which should be abstracted in the model layer. So here is how I deal with the problem these days:
-
class User extends AppModel{
-
}
-
'action' => $action,
-
), $options);
-
}
-
return $record[$options['model']]['user_id'] == User::get('id');
-
}
-
}
-
-
class Post extends AppModel{
-
if ($options['action'] == 'view' && $record['Post']['published']) {
-
return true;
-
}
-
return ($record['Post']['user_id'] == User::get('id')) || User::isAdmin();
-
}
-
}
-
-
class PostsController extends Controller{
-
function view($id = null) {
-
$post = $this->Post->findById($post);
-
}
-
-
function edit($id = null) {
-
$post = $this->Post->findById($post);
-
}
-
}
-
This is quite some code for this refactoring, yet I found it extremly nice to work with this pattern torwards data access control. It is fairly light weight compared to most other approaches, yet gives you a per-Model and per-Context kind of flexibility on access control.
Let me know if you have any questions!
HTH,
-- Felix Geisendörfer aka the_undefined