Yii 中的 RBAC - 访问检查


RBAC in Yii - access checking

我设置了角色、任务和操作层次结构,并将其分配给用户,操作镜像控制器:操作。

从文档中,如果我想检查用户是否有权访问操作,我会检查,例如:

if(Yii::app()->user->checkAccess('createPost'))

这给人的印象是,我必须在每个操作中手动添加代码,以检查用户是否有权使用相应的角色。我是否错过了什么 - 当然有一种方法可以为每个操作自动执行此操作。

我可能会扩展基本的控制器类并添加一些东西(在preFilter中?)使用Yii::app()->controller和Yii::app()->controller->action来生成角色,然后检查用户是否被授权担任该角色。

但我相信一定已经有办法做到这一点了?

我知道accessRules过滤器允许您传递角色,但这似乎违背了拥有角色>任务>操作层次结构的目的,并且必须为每个操作分配此类规则几乎与首先检查每个功能一样糟糕。

我是否缺少其他选项,可以自动检查执行/item/delete 的用户是否有权执行"item:delete"操作(或 DB AuthItem 表中预期的任何格式)?

编辑
澄清我在数据库 RBAC 中使用访问规则的问题:

我在数据库中定义了一个角色结构 - 许多角色,每个角色被授权执行多个任务,这些任务又由精细操作组成(例如,角色"读者"可能被授权执行"浏览帖子"任务,它由"帖子/索引"和"帖子/视图"组成)。然后,我将用户分配给一个角色,该角色授予他们访问该角色的任务以及这些任务中的操作的权限。如果我随后调用 user->checkAccess 进行控制器操作(即操作),它会在数据库中检查用户是否有权使用包含任务(包括该操作)的角色。

但是,如果我遍历每个控制器并定义每个操作授权的角色,我正在重复我在数据库中已经完成的工作,可能会有冲突的规则。

过滤器似乎已经完成了这个技巧。

假设你在受保护/组件/控制器.php中定义了基本控制器,请向其添加以下函数以定义筛选器。如果由于某种原因没有基控制器类,请在单独的类中定义筛选器,如控制器文档中所述。无论如何,这样做可能会更好(更可重用)。

public function filterAccessControl($filterChain)
{
    $controller = Yii::app()->controller->id;
    $action = Yii::app()->controller->action->id;
//The RBAC admin module I'm using creates entries for operations as, e.g. Post:Create
// You may need to change this to match whatever entry format you have in your AuthItem table
    $operation = ucfirst($controller) . ':' . ucfirst($action);
    Yii::log('Checking auth for user: ' . Yii::app()->user->id. ' to operation: ' . $operation, 'info');
    if(Yii::app()->user->checkAccess($operation))
    {
        Yii::log('User authorised', 'info');
        $filterChain->run();
        return true;
    }
    else
    {
        Yii::log('Unauthorised user!!!!!', 'info');
        throw new CHttpException(401, 'You are not authorized to perform this action.');            
        return false;
    }   
}

(我正在使用 RBAM 来管理数据库中的身份验证表,该表将操作名称存储为 ControllerName:ActionName,因此是 ucfirst)。

要为每个控制器中的每个操作运行此筛选器,请通过添加 filters() 函数来应用筛选器,再次在控制器中.php:

public function filters()
{
    return array(
   'accessControl',
);
}

一些注意事项:

  • 如果你的任何控制器中都有现有的过滤器,你需要在那里应用这个过滤器,因为控制器 filters() 函数将覆盖这个过滤器
  • 无论如何,在每个
  • 控制器中单独执行此操作可能会更安全,因为如有必要,如果出于某种原因您想要一些异常,您可以限制过滤器适用的操作。另外,如果您只在这里执行此操作,然后忘记并稍后将其他过滤器添加到某些控制器,您将失去对这些过滤器的访问控制!
  • 在执行此操作之前,请确保您已在 authManager 配置中配置了默认来宾角色,并且该角色有权访问/site/login。否则您将无法登录!(如果发生这种情况,只需禁用过滤器,直到您将其整理出来)

我的回答可能不会对这个问题有太多新的了解:

最终,应用程序无法猜测允许谁执行每个操作。你必须告诉Yii谁被允许做什么动作 - 这种方式(可能更长)或另一种方式(可能更短)。

您可以通过"长途"来执行此操作,即在每个操作方法的开头添加"checkAccess()",并在用户没有访问权限时使用自定义消息做出反应。请注意,这种方式即使很长,也是冗长和干净的,这导致代码的维护更容易。

正如您所指出的,您还可以使用"访问控制过滤器"和"访问规则"方法。这更短,但对于局外人来说不太清楚(可能是你,在离开代码的那个心理区域几个月后),因此代码不太可维护,恕我直言。

我确实想指出,将"访问控制过滤器"与 RBAC 一起使用并不矛盾或破坏非常好的权限层次结构。请记住,此层次结构由相互继承的角色组成,每个角色由任务和可能的操作组成 (YMMV.我通常做相互继承的角色,每个角色都"由"任务组成,其中一些任务具有 bizrules)。如果你能详细说明为什么你认为这将"破坏拥有角色>任务>操作层次结构"的目的,而这个层次结构对这次讨论来说是富有成效的。

使用 yii-auth 怎么样? https://github.com/Crisu83/yii-auth

您可以避免检查每个地方 - if(Yii::app()->user->checkAccess('createPost'))并使用类似的东西

public function filters()
{
  return array(
    array('auth.filters.AuthFilter'),
  ),
}