Zend ACL Dynamic Assertion

无人久伴 提交于 2019-12-12 16:12:14

问题


I want to restrict my users to edit/delete only the comments which they added. I found an example on youtube by a guy named intergral30 and followed his instruction. And now my admin account has the possibility to edit/delete everything, but my user has no access to his own comment.

Here's the code: Resource

class Application_Model_CommentResource implements Zend_Acl_Resource_Interface{
public $ownerId = null;
public $resourceId = 'comment';

public function getResourceId() {
    return $this->resourceId;
}
}

Role

class Application_Model_UserRole implements Zend_Acl_Role_Interface{
public $role = 'guest';
public $id = null;

public function __construct(){
    $auth = Zend_Auth::getInstance();
    $identity = $auth->getStorage()->read();

    $this->id = $identity->id;
    $this->role = $identity->role;
}

public function getRoleId(){
    return $this->role;
}
}

Assertion

class Application_Model_CommentAssertion implements Zend_Acl_Assert_Interface
{
public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $user=null,
            Zend_Acl_Resource_Interface $comment=null, $privilege=null){
    // if role is admin, he can always edit a comment
    if ($user->getRoleId() == 'admin') {
        return true;
    }

    if ($user->id != null && $comment->ownerId == $user->id){
        return true;
    } else {
        return false;
    }
}

}

In my ACL I have a function named setDynemicPermissions, which is called in an access check plugin's preDispatch method.

public function setDynamicPermissions() {
    $this->addResource('comment');
    $this->addResource('post');

    $this->allow('user', 'comment', 'modify', new Application_Model_CommentAssertion());

    $this->allow('admin', 'post', 'modify', new Application_Model_PostAssertion());
}

public function preDispatch(Zend_Controller_Request_Abstract $request) 
{
    $this->_acl->setDynamicPermissions();
}

And I'm calling the ACL-s isAllowed method from my comment model where I return a list of comment objects.

public function getComments($id){
    //loading comments from the DB

    $userRole = new Application_Model_UserRole();
    $commentResource = new Application_Model_CommentResource();

    $comments = array();
    foreach ($res as $comment) {
        $commentResource->ownerId = $comment[userId];

        $commentObj = new Application_Model_Comment();
        $commentObj->setId($comment[id]);
        //setting the data
        $commentObj->setLink('');

        if (Zend_Registry::get('acl')->isAllowed($userRole->getRoleId(), $commentResource->getResourceId(), 'modify')) {
            $commentObj->setLink('<a href="editcomment/id/'.$comment[id].'">Edit</a>'.'<a href="deletecomment/id/'.$comment[id].'">Delete</a>');
        }

        $comments[$comment[id]] = $commentObj;
    }
}

Can anyone tell me what have I done wrong? Or what should I use if I want to give my admins the right to start a post and other users the right to comment on them. Each user should have the chance to edit or delete his own comment and an admin should have all rights.


回答1:


You seem to be using the dynamic assertions in a wrong manner, as you are still passing the roleId to isAllowed().

What these dynamic assertions really do, is take a complete object and work with it. Zend will determine which rule has to be used by calling getResourceId() and getRoleId() on your objects.

So all you have to do is pass your objects instead of the strings to isAllowed():

public function getComments($id){
    //loading comments from the DB

    $userRole = new Application_Model_UserRole();
    $commentResource = new Application_Model_CommentResource();

    $comments = array();
    foreach ($res as $comment) {
        $commentResource->ownerId = $comment[userId];

        $commentObj = new Application_Model_Comment();
        $commentObj->setId($comment[id]);
        //setting the data
        $commentObj->setLink('');

        // This line includes the changes
        if (Zend_Registry::get('acl')->isAllowed($userRole, $commentResource, 'modify')) {
            $commentObj->setLink('<a href="editcomment/id/'.$comment[id].'">Edit</a>'.'<a href="deletecomment/id/'.$comment[id].'">Delete</a>');
        }

        $comments[$comment[id]] = $commentObj;
    }
}

But in can be done better

You would not have to implement a total new Application_Model_CommentResource, but instead you can use your actual Application_Model_Comment like this:

// we are using your normal Comment class here
class Application_Model_Comment implements Zend_Acl_Resource_Interface {
    public $resourceId = 'comment';

    public function getResourceId() {
        return $this->resourceId;
    }

    // all other methods you have implemented
    // I think there is something like this among them
    public function getOwnerId() {
        return $this->ownerId;
    }
}

Assertion would then use this object and retrieve the owner to compare it with the actually logged in person:

class Application_Model_CommentAssertion implements Zend_Acl_Assert_Interface {
    public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $user=null,
        Zend_Acl_Resource_Interface $comment=null, $privilege=null){
    // if role is admin, he can always edit a comment
    if ($user->getRoleId() == 'admin') {
        return true;
    }

    // using the method now instead of ->ownerId, but this totally depends
    // on how one can get the owner in Application_Model_Comment
    if ($user->id != null && $comment->getOwnerId() == $user->id){
        return true;
    } else {
        return false;
    }
}

And the usage is like this:

public function getComments($id) {
    //loading comments from the DB

    $userRole = new Application_Model_UserRole();

    $comments = array();
    foreach ($res as $comment) {
        $commentObj = new Application_Model_Comment();
        $commentObj->setId($comment[id]);
        //setting the data
        $commentObj->setLink('');

        // no $commentResource anymore, just pure $comment
        if (Zend_Registry::get('acl')->isAllowed($userRole, $comment, 'modify')) {
            $commentObj->setLink('<a href="editcomment/id/'.$comment[id].'">Edit</a>'.'<a href="deletecomment/id/'.$comment[id].'">Delete</a>');
        }

        $comments[$comment[id]] = $commentObj;
    }
}


来源:https://stackoverflow.com/questions/11668785/zend-acl-dynamic-assertion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!