There's more to an application than its controllers and action methods. Sometimes you want to allow a user to access a controller and action, but only when that user is working with content objects that he owns within that system. For example, a user might be allowed to edit blog entries, but only his *own* blog entries. In these cases, we need to know if the current user is the owner of the blog entry he is attempting to work with.
First, you need to add a special method on your content objects.
In the example, we will call the method
accessIsOwner()
, but you can call it whatever you
like.
The special ownership method on your content object should take
two params in this order: a Solar_Auth_Adapter instance, and a
Solar_Role_Adapter instance. The method you write can then check
the current user's authenticated identity and/or assigned roles,
and then return true
if the user is considered
an owner of the content object (or false
if
not).
As an example, let's say we have a model record for a blogs entry,
and that the database table for that model includes a column
called author_handle
(i.e., the username handle
of the person who created the blog entry). We could write a method
like this on the blogs record class:
<?php
class Vendor_Model_Blogs_Record
{
public function accessIsOwner(Solar_Auth_Adapter $auth, Solar_Role_Adapter $role)
{
// check the record's 'author_handle' column to see
// if it matches the current authenticated user.
if ($this->author_handle == $auth->handle) {
return true;
}
// not the original author, so don't treat as an owner.
return false;
}
}
For each kind of content object in the system, you will need to
tell Solar_Access_Adapter what method to use on each object to
determine if the user is an owner or not. In the above example, we
have the Vendor_Model_Blogs_Record::accessIsOwner()
method. We make a corresponding entry in the
'owner_method'
config key for
Solar_Access_Adapter:
<?php
$config['Solar_Access_Adapter']['owner_method'] = array(
'Vendor_Model_Blogs_Record' => 'accessIsOwner',
);
The 'owner_method'
config setting is an array of
key-value pairs where the key is the class name of the object
being checked, and the value is the method on that class. Later,
when we call $user->access->isOwner()
, the
adapter will loop through these keys, see if the object being
controller matches a class in the array, and call the
corresponding method to check ownership.
As noted in an earlier section, you can use an
'owner'
entry type to specify that the user has
to be the owner of an object being checked in the controller and
action.
# flag type name class action # ---- ---- ---- ----- ------ # allow users to edit their own posts allow owner - Vendor_App_Blog edit
Now that we have the special ownership method on our content class, and the access adapter knows what methods to check on which content classes, we can integrate an ownership access check in our controller actions.
Using the "Intra-Action Access Control" approach from the previous section, adding ownership checks would look like this:
<?php
abstract class Vendor_Controller_Page extends Solar_Controller_Page
{
public $user;
protected function _setup()
{
parent::_setup();
$this->user = Solar_Registry::get('user');
}
protected function _isUserAllowed($object = null)
{
if ($this->user->access->isAllowed($this, $this->_action, $object)) {
return true;
} else {
$this->_error('Access denied.');
$this->_response->setStatusCode(403);
return false;
}
}
}
class Vendor_App_Blog extends Vendor_Controller_Page
{
public function actionEdit($id = null)
{
// ... perform preliminary logic ...
// get the blog item for editing
$item = $this->_model->blogs->fetch($id);
// check access
if (! $this->_isUserAllowed($item)) {
return;
}
// ... rest of the action here ...
}
}
-
In the
_isUserAllowed()
method, we have added a single parameter to allow passing of a content object for ownership checks. Likewise, the call toisAllowed()
passes the content object along for checking. -
The
actionEdit()
method retrieves the blog entry before checking access controls. Only after the entry is retrieved do we check to see if the user is allowed to access this object within the context of this controller and action.