Zend Acl - 当 acl 规则返回 false 时,断言是否可以允许访问特权?

发布于 2024-11-02 15:22:25 字数 2971 浏览 1 评论 0原文

默认情况下,即使 acl 规则允许,在断言中返回 false 也会拒绝访问。我想要做的是相反的 - 即在断言中返回 true,以在 acl 规则拒绝访问时允许访问。

例如:

class TestAssert implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)
    {
        return true;
    }
}

$acl = new Zend_Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->allow('user', 'page', 'read', new TestAssert);
$acl->isAllowed('user', 'page', 'write');

上面的 isAllowed() 将返回 false,因为我所询问的权限在 acl 规则中是不允许的,因此它没有达到断言的程度。

我想要的可能吗?

我想这样做的原因是,用户可能对所有页面拥有某些权限,然后对他们创建的页面拥有一组不同的权限 - 当查询权限时,我希望能够判断该页面是否是他们的,以及是否也就是说,应用“自己页面”的规则,而不是“页面”。显然,在真实的应用程序中,传递的是用户和页面对象而不是字符串。

更新:我已经成功地通过子类化 Zend_Acl 来完成我想做的事情。

此类允许为特定角色和资源组合添加回调。当调用 isAllowed() 时,回调(如果存在)将运行。它以与断言相同的参数传递(以及parent::isAllowed() 的结果)。该回调的返回值是从 isAllowed() 返回的,除非它为 null,在这种情况下使用正常的返回值。

class Acl extends Zend_Acl
{
    protected $_callbacks = array();

    /**
     * Takes into account the callback to determine whether the role is allowed access
     * 
     * @param Zend_Acl_Role_Interface $role
     * @param Zend_Acl_Resource_Interface $resource
     * @param string $privilege
     * @return bool
     */
    public function isAllowed($role = null, $resource = null, $privilege = null)
    {
        $result = parent::isAllowed($role, $resource, $privilege);
        $role = $this->getRole($role)->getRoleId();
        $resource = $this->get($resource)->getResourceId();

        if(isset($this->_callbacks[$role][$resource]))
        {           
            $callbackResult = call_user_func($this->_callbacks[$role][$resource], $this, $role, $resource, $privilege, $result);
        }

        return isset($callbackResult) ? $callbackResult : $result;
    }

    /**
     * Add a callback for a specific role and resource combination.
     * If the callback returns a value, this is used as the return value for isAllowed().
     * Otherwise, if the callback returns null, the normal result of isAllowed() will be used.
     * 
     * @param Zend_Acl_Role_Interface $role
     * @param Zend_Acl_Resource_Interface $resource
     * @param callback $callback 
     */
    public function addCallback($role, $resource, $callback)
    {
        $role = $this->getRole($role)->getRoleId();
        $resource = $this->get($resource)->getResourceId();
        $this->_callbacks[$role][$resource] = $callback;
    }
}

用法:

$acl = new Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->addCallback('user', 'page', function($acl, $role, $resource, $privilege, $result)
{
    return true;
});


$acl->allow('user', 'page', array('read'));
$acl->isAllowed('user', 'page', 'edit'); //returns true even though 'edit' is not allowed.

By default, returning false in an assertion denies access even when the acl rules allow it. What I want to do is the other way round - i.e. return true in an assertion to allow access when the acl rules deny it.

For example:

class TestAssert implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)
    {
        return true;
    }
}

$acl = new Zend_Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->allow('user', 'page', 'read', new TestAssert);
$acl->isAllowed('user', 'page', 'write');

The above isAllowed() will return false because the privilege I am asking about is not allowed in the acl rules, therefore it isn't getting as far as the assertion.

Is what I want possible?

The reason I want to do this is that a user may have certain privileges for all pages and then a different set of privileges for pages they have created - when querying for a privilege I want to be able to tell if the page is theirs and if it is, apply the rules for "own-page" rather than "page". Obviously in the real app, user and page objects are passed instead of strings.

UPDATE: I have managed to do what I want by subclassing Zend_Acl.

This class allows callbacks to be added for specific role and resource combinations. When isAllowed() is invoked, the callback, if it exists, is run. It is passed in the same parameters as an assertion (as well as the result of parent::isAllowed()). The return value of this callback is return from isAllowed(), unless it is null, in which case the normal return value is used.

class Acl extends Zend_Acl
{
    protected $_callbacks = array();

    /**
     * Takes into account the callback to determine whether the role is allowed access
     * 
     * @param Zend_Acl_Role_Interface $role
     * @param Zend_Acl_Resource_Interface $resource
     * @param string $privilege
     * @return bool
     */
    public function isAllowed($role = null, $resource = null, $privilege = null)
    {
        $result = parent::isAllowed($role, $resource, $privilege);
        $role = $this->getRole($role)->getRoleId();
        $resource = $this->get($resource)->getResourceId();

        if(isset($this->_callbacks[$role][$resource]))
        {           
            $callbackResult = call_user_func($this->_callbacks[$role][$resource], $this, $role, $resource, $privilege, $result);
        }

        return isset($callbackResult) ? $callbackResult : $result;
    }

    /**
     * Add a callback for a specific role and resource combination.
     * If the callback returns a value, this is used as the return value for isAllowed().
     * Otherwise, if the callback returns null, the normal result of isAllowed() will be used.
     * 
     * @param Zend_Acl_Role_Interface $role
     * @param Zend_Acl_Resource_Interface $resource
     * @param callback $callback 
     */
    public function addCallback($role, $resource, $callback)
    {
        $role = $this->getRole($role)->getRoleId();
        $resource = $this->get($resource)->getResourceId();
        $this->_callbacks[$role][$resource] = $callback;
    }
}

Usage:

$acl = new Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->addCallback('user', 'page', function($acl, $role, $resource, $privilege, $result)
{
    return true;
});


$acl->allow('user', 'page', array('read'));
$acl->isAllowed('user', 'page', 'edit'); //returns true even though 'edit' is not allowed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只有影子陪我不离不弃 2024-11-09 15:22:25

听起来您想要类似的内容:

class WriteAssert implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl,
                           Zend_Acl_Role_Interface $role = null,
                           Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)
    {
        // return whether the user owns the page
    }
}

$acl = new Zend_Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->allow('user', 'page', 'read');
$acl->allow('user', 'page', 'write', new WriteAssert);
$acl->isAllowed('user', 'page', 'write');

在这里,您希望用户能够读取任何页面,但只能写入自己的页面。

Sounds like you want something along the lines of:

class WriteAssert implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl,
                           Zend_Acl_Role_Interface $role = null,
                           Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)
    {
        // return whether the user owns the page
    }
}

$acl = new Zend_Acl;
$acl->addResource('page');
$acl->addRole('user');

$acl->allow('user', 'page', 'read');
$acl->allow('user', 'page', 'write', new WriteAssert);
$acl->isAllowed('user', 'page', 'write');

Here you would expect the user to be able to read any page but only write to their own pages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文