Zend ACL动态断言

时间:2012-07-26 11:57:43

标签: zend-framework dynamic acl assertion

我想限制我的用户只编辑/删除他们添加的评论。我在youtube上找到了一个名为intergral30的人并按照他的指示操作的例子。现在我的管理员帐户可以编辑/删除所有内容,但我的用户无法访问自己的评论。

这是代码: 资源

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

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

作用

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;
}
}

断言

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;
    }
}

}

在我的ACL中,我有一个名为setDynemicPermissions的函数,它在访问检查插件的preDispatch方法中调用。

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();
}

我正在从我的评论模型中调用ACL-s 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('');

        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;
    }
}

谁能告诉我,我做错了什么? 或者如果我想让我的管理员有权发起帖子而其他用户有权评论他们,我该怎么用。每个用户都应该有机会编辑或删除自己的评论,管理员应该拥有所有权利。

1 个答案:

答案 0 :(得分:5)

您似乎以错误的方式使用动态断言,因为您仍然将roleId传递给isAllowed()

这些动态断言真正做的是获取一个完整的对象并使用它。 Zend将通过在您的对象上调用getResourceId()getRoleId()来确定必须使用哪条规则。

所以你要做的就是将对象而不是字符串传递给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;
    }
}

但是可以做得更好

您不必实施全新Application_Model_CommentResource,而是可以使用您的实际Application_Model_Comment

// 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然后将使用此对象并检索所有者以将其与实际登录的人进行比较:

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;
    }
}

用法是这样的:

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;
    }
}