3

我正在为自定义框架的访问控制实现而苦苦挣扎。

不需要 RBAC 粒度,因此我决定使用某种 ACL,其中资源将成为控制器操作。

下面是数据库结构:

用户:

  • 约翰
  • 玛丽
  • 格雷格

用户组:

  • 管理员
  • 会计师
  • 经理人

users_to_user_groups:

  • 约翰 => 管理员
  • 玛丽 => 会计师
  • 格雷格 => 经理

资源(控制器操作):

  • 用户/编辑
  • 发票/添加
  • 客户/删除

resources_to_user_groups:

  • 用户/编辑 => 管理员
  • 发票/添加 => 会计师
  • 客户/删除 => 经理

这是[伪]代码。

$user = new User; // This will be currently logged in user ...

$acl = new Acl($user);

$dispatcher = new Dispatcher($acl);

$dispatcher->dispatch('users', 'new');

class Dispatcher
{
    public function dispatch($controller, $action)
    {
        $permission = $controller . '/' . $action;

        if(!$this->acl->isAllowed($permission))
        {
            throw new AccessDeniedException("Access denied");
        }

        // User is authorized to execute this action, dispatch ...
    }
}

我喜欢这种方法……直到我意识到还有很多 XHR 请求。

例如,发票列表使用 XHR 请求获取总金额,订单列表使用 XHR 请求加载订单位置和其他数据等。

所以,必须有一些资源分组,例如新表resource_groups:

  • 发票清单(invoices/list, invoices/xhr_get_total_amount)
  • 订单列表(orders/list、orders/xhr_get_positons_for_order、orders/xhr_get_some_other_data)
  • 添加新用户 (users/new) # 单个动作,新用户输入表单不使用 XHR 请求

...而不是将资源分配给用户组,而是将资源组分配给用户组。

感觉好复杂 这是正确的方法吗?有什么可以改进的?有什么框架可以解决这个问题吗?

4

4 回答 4

2

为什么不向resources表中添加新列,称为descendants,它将存储一个依赖 xhr 资源的数组?所以它可能看起来像:

resource: "invoices/list"
descendants: ["invoices/xhr_get_total_amount"]

resource: "orders/list"
descendants: ["orders/xhr_get_positons_for_order","orders/xhr_get_some_other_data"]

resource: "users/new"
descendants: []

此外,如果尚未实现:您可以在请求开始时获取并处理允许资源及其后代的整个列表到单个数组,并将它们存储到响应。因此,每次需要检查访问权限时,您都不会询问数据库。

于 2013-05-25T19:39:24.087 回答
2

在过去的一年里,我一直在处理同样的问题,这就是我解决它的方法。

首先,我使用Zend Framework 的 ACL库作为基础引擎来告诉我某个用户是否可以访问某些资源。由于 ZF 已经支持用户分组和角色(包括角色层次结构),您无需再担心这一点。

将用户分组和角色放在一边,接下来是 ZF 内部不支持的资源分组(遗憾的是)。我相信这是您的问题所关注的部分。然而,您可以使用 ZF 并对其进行扩展以满足您的需求。您需要做的就是为资源(平面或分层)提出一个分组机制。然后您可以按照手册中的说明使用 ZF。

这是有关如何执行此操作的示例:

  1. 构造 ACL 引擎和其他基本对象:

    $acl = new Zend_Acl();
    
    $acl->addRole(new Zend_Acl_Role('guest'))
        ->addRole(new Zend_Acl_Role('member'))
        ->addRole(new Zend_Acl_Role('admin'));
    
    $parents = array('guest', 'member', 'admin');
    $acl->addRole(new Zend_Acl_Role('someUser'), $parents);
    
  2. 定义您的资源分组:

    $resources = array(
        'group 1' => array(
            'resource 1'
            , 'resource 2'
            , 'resource 3'
        )
        , 'group 2' => array(
            'resource 1'
            , 'resource 4'
            , 'resource 5'
        )
    );
    
  3. 将您的资源引入 ACL 的引擎:

    function addResource(Zend_Acl $acl, $resources, $groupName)
    {
        foreach ($resources[$groupName] as $resource) {
            $acl->add(new Zend_Acl_Resource($resource));
        }
    }
    
    addResource($acl, $resources, 'group 2');
    
  4. 使用 ACL 的引擎查询权限:

    echo $acl->isAllowed('someUser', 'resource 1') ? 'allowed' : 'denied';
    

如您所见,我在这里没有做任何特别的事情。这里引入的唯一新概念是添加到 ACL 引擎的资源与用于查询它的资源不同。但是在我们实际调用 ZF 的库之前已经完成了一层,因此查询 ZF 的 ACL 的调用仍然有效。

我希望我能清楚地写下我的观点。别忘了我只是想给你一个概念,你需要自己想出实际的实现。

于 2013-05-28T04:54:44.467 回答
1

我知道我没有直接回答您的问题,但也许我可以将您发送到一条稍微不同的路径,一旦您的网站规模和复杂性增加,这条路径将变得更加灵活。阅读这篇文章后,我已将身份验证系统切换为基于活动(允许活动“doSomething”),而不是基于角色(“管理员”可以执行以下操作......)。

只是一个想法。

于 2013-05-23T01:57:30.000 回答
1

最好不要使用 * 而是使用请求文件的域。* 在某些版本的 IE 中会失败(不记得了)。

if ($ref_url)
  header("Access-Control-Allow-Origin:"+$ref_url);
else
  header("Access-Control-Allow-Origin:*");
于 2013-05-25T15:55:35.217 回答