细粒度的访问控制

时间:2009-10-04 22:35:57

标签: php mysql authorization access-control

我熟悉为我们正在开发的基于Web的管理应用程序验证用户的一系列方法,甚至还有各种技术来密切授权......

但是,我的问题是,您如何建议我实施提供以下内容的细粒度访问控制机制:

  1. 用户属于“角色”或“群组”,例如“营业员”,“计划”等。
  2. 管理菜单系统仅显示具有与用户角色相关的功能的“页面”
  3. 这些页面中的特定功能有限制 - 例如,在“新预订”页面上,“销售人员”用户可以“仅在将来”发出预订,在“编辑预订”页面上可以编辑预订从现在起一周'。但是,“规划”用户可能会被允许在“任何时间段”内追溯预订,并编辑自己在“任何时间段”内所做的预订,但其他人仅在“直到明天”预订时才会进行预订...
  4. 我知道我可以实现一个基本的基于角色的系统来满足no.1 ...我有一种感觉我应该将整个应用程序拆分成代码块,每个代码块都有自己的objectID-permissionID关系,这样我就可以扫描有权查看哪些对象可用的权限数据库 - 这对我有帮助。

    我可以构建表单控件的任何想法,例如,对于'销售'用户仅显示未来的日期(但是为计划用户显示“一周前”的日期),然后以某种方式将其与POST解析器中的行检查日期是否实际上在预期范围内?

    我已经尝试过将每个代码块保存到数据库的想法,然后有一个对象表根据权限表动态构建代码,以便服务器上唯一的“文件”是db连接文件!

    欢迎任何想法......(即使你的背景不是php / MySQL)


    Zed Shaw在谈到为什么“ACL已经死亡”时,对CUSEC演讲中的问题有了更深入的了解 - http://vimeo.com/2723800

4 个答案:

答案 0 :(得分:4)

警告,很多Zend Framework都在前面!

您可以使用Zend_AclZend_Navigation轻松处理1.和2.

对于数字3,您将不得不在模型中查询ACL对象并手动执行大量操作。您也可以将Zend Framework用于表单,并根据用户角色权限包含特定的表单元素验证器。

修改

如果您不想使用ZF路线,至少可以看一看如何在ZF中处理ACL。

答案 1 :(得分:2)

如果您想构建真正的细粒度访问控制(FGAC),请查看我关于MySQL的这个主题的文章:

MySQL 5.0 Fine-Grained Access Control (FGAC)

基本上,您不希望业务代码依赖于FGAC实现,您不希望在业务规则的where语句的select子句中混合使用FGAC代码。 本文介绍了避免SQL语句混乱的解决方案。

答案 2 :(得分:1)

为了实现“原生”​​方法,而不是捎带框架,我一直在玩下面的内容。有人会评价这种方法吗?你预见到任何陷阱吗?

// Check database for existence of this $user against this $object.
function get_permission($user, $object){
    // Query goes here...
    if( ... ){
        return $permission;
    } else {
        return FALSE;
    }
}

上述函数将查询数据库并输出如下内容:

// Result of role-object query.  
role_ID      object_ID          permission  
-------      ---------          ----------
salesperson  new_booking_date   'min' => 'now', 'max' => '+1 year'  
planning     new_booking_date   'min' => '-1 week', 'max' => '+1 year'  
salesperson  edit_booking_date  'this_user_min' => 'now', 'this_user_max' => '+1 week', 'other_user_min' => 'now', 'other_user_max' => '+1 week'  
planning     edit_booking_date  'this_user_min' => '-1 week', 'this_user_max' => '+1 year', 'other_user_min' => '-1 week', 'other_user_max' => '+1 week'  

包含表单输入的页面中的以下代码:

// Draw form control with javascript date validation...
$this_permission = get_permission($this_user, 'new_booking_date');
if($this_permission){
    $html->datepicker('min' => $this_permission['min'], 'max' => $this_permission['max']);
}

预订完成后,另一页允许我们编辑该字段:

// Verify POST data...
$this_permission = get_permission($this_user, 'edit_booking_date');
if($this_permission){
    if($this_user == $author_user && $_POST['date'] >= strtotime($this_permission['this_user_min'], $date_ref) && $_POST['date'] <= strtotime($this_permission['this_user_max'], $date_ref)){
        // Update database...
    } elseif($_POST['date'] >= strtotime($this_permission['other_user_min'], $date_ref) && $_POST['date'] <= strtotime($this_permission['other_user_max'], $date_ref)){
        // Update database...
    }
}

我是否在轨道上?

答案 3 :(得分:0)

我开发了一个名为PHP-Bouncer的库,我认为它可以很好地满足您的需求。它目前支持完全托管访问,允许您在每个页面上使用单个调用(我建议使用包括当然),并且如果他们无权访问页面,则自动重定向人员,以及自动从中检索角色数据库(如果使用包含的MySQL表设置脚本在DB中实现角色)。语法非常简单。

您创建了保镖:

$bouncer = new Bouncer();

添加角色(手动):

// Add a role     Name,      Array of pages role provides
    $bouncer->addRole("Public", array("index.php", "about.php", "fail.php"));
// Add a role          Name,              Array of pages role provides
    $bouncer->addRole("Registered User", array("myaccount.php", "editaccount.php", "viewusers.php"));
// Add a role          Name,   Array of pages role provides       List of pages that are overridden by other pages
    $bouncer->addRole("Admin", array("stats.php", "manageusers.php"), array("viewusers.php" => "manageusers.php"));

或来自数据库:

// conf_* values are set in a config file, or you can pass them in explicitly
$bouncer->readRolesFromDatabase(conf_hostname, conf_username, conf_password, conf_schema, "mysql");

添加用户并为他们提供一些角色(注意:有一个名为BouncerUser的类,您的User类可以扩展,它提供您需要的所有角色功能!):

$user->addRole("Logged In"); // This Role doesn't exist in the bouncer, but we can set it anyways if we feel like setting another flag on the user's account. This can be useful for displaying content in a page only if a user has a secondary role.
$user->addRole("Public");
$user->addRole("Registered User");

然后让Bouncer管理对您文件的访问:

$bouncer->manageAccess($user->getRoles(), substr($_SERVER["PHP_SELF"], 1), "fail.php");
// Any time the user tries to go to a page they don't have access to, they will get to
// fail.php. Any time they try to go to a page that is overridden for them, they will 
// get to the overriding page.

如果您希望仅在用户有权查看页面时才在页面中显示内容,只需将其包装在:

if($user->hasRole("Registered User")){
    echo "The content";
}

我认为对于您所描述的问题,这将是一个很好的解决方案!