【问题标题】:Yii's accessRules misconceptionYii 的 accessRules 误解
【发布时间】:2013-01-09 16:04:41
【问题描述】:

我正在尝试使用 Yii 构建一个站点,发现自己处于需要对 Yii 中的访问控制隐喻进行一些澄清的情况。具体来说,可以覆盖CController 的后代中的accessRules 方法。

先决条件:

这里是Gii默认生成的代码,和documentation很像:

public function accessRules()
{
    return array(
        array('allow',  // allow all users to perform 'index' and 'view' actions
            'actions'=>array('index','view'),
            'users'=>array('*'),
        ),
        array('allow', // allow authenticated user to perform 'create' and 'update' actions
            'actions'=>array('create','update'),
            'users'=>array('@'),
        ),
        array('allow', // allow admin user to perform 'admin' and 'delete' actions
            'actions'=>array('admin','delete'),
            'roles'=> array('admin'),
        ),
        array('deny',  // deny all users
            'users'=>array('*'),
        ),
    );
}

问题:

我不清楚的是——为什么我们需要为许多不同的用户和组以及不同的操作定义访问规则,而不是只检查一个当前用户和操作的权限? -- 这里用斜体字突出显示了我的主要问题,以防读者(答案作者)可能不太清楚。

此代码在特定请求的上下文中执行,已知特定的controller、特定的action 和特定的user。例如,如果用户是来宾,我看不出有任何理由为“管理员”角色或经过身份验证的用户定义规则。

推理:

经过一番阐述,我想出了以下实现:

public function accessRules()
{
    return array(
      array(Yii::app()->user->hasRights()?'allow':'deny'),
      );
}

其中hasRights 是添加到CWebUser 后代中的简单自定义方法:

class WebUser extends CWebUser
{
  private $ACL = // ACL example
    array('user' => // controller id
      array('index' => User::AC_MODERATOR, // action ids
            'view' => User::AC_MODERATOR,
            'create' => User::AC_MODERATOR,
            'update' => User::AC_ADMIN,
            'delete' => User::AC_ADMIN,
            'admin' => User::AC_ADMIN),
           // ...
      );

  public function hasRights()
  {
    return (Yii::app()->user->getState('accessRights') >=
      $this->ACL[Yii::app()->controller->id][Yii::app()->controller->action->id]);
  }
}

如您所见,hasRights 使用当前用户“权限”(照常从 DB 中读取)、当前控制器和操作来计算单个布尔值 truefalse 值作为访问决策。

这种方法有什么问题?为什么 Yii 默认不使用这么简单的东西?

上面的 Gii 生成的accessRules 不仅看起来多余,而且暗示访问规则分散在许多控制器中。在我的方法中,使用了单一且紧凑的 ACL。

【问题讨论】:

    标签: php access-control yii


    【解决方案1】:

    这就是我认为你感到困惑的地方。

    首先,Yii 实际上只关注当前用户和当前操作。就像你通过抓取一个嵌套数组来获得控制器的当前权限一样,由控制器 ID 索引,Yii 正在创建你的控制器的一个实例,并且只查看那些访问规则。此外,就像您只查看特定操作的权限一样,Yii 仅查看与当前操作相关的规则。它访问这些权限就像您返回嵌套数组的值一样容易。

    就用户而言,它也只是查看当前用户;当前用户名、当前用户角色等。不同之处在于,Yii 允许在一个规则中使用多个属性,而不是与用户关联的单个权限值。

    您不喜欢这种方法的地方似乎是您认为应该在一个地方处理所有权限。这在某些情况下可能更简单,但在其他情况下更困难。当您有多个控制器和每个控制器中的多个操作时会发生什么?您现在有一个非常大的数组要管理,它引用来自多个不同上下文的数据。 Yii 的做法是,当前控制器可以控制如何访问它的数据结构。这符合 Yii 的 MVC 结构,以及封装的概念。

    您的解决方案在某些方面更优雅,但它取决于这样一种想法,即权限只需要在一个级联的单向结构中构建。我的意思是您的权限就像一条长长的走廊,门将一个区域与另一个区域隔开。如果用户没有一扇门的钥匙,他们应该无法访问下一扇门,等等。但是,在您的示例中,如果您需要用户既查看内容又更新内容而无法访问,会发生什么情况创建新内容?这是一个更复杂的场景,需要使用角色来处理。所以你必须在你的数组中处理规则,就像 Yii 一样。除了 Yii 的面向对象方法之外,您将所有内容都嵌入到一个长数组中。

    所以也许你的解决方案在某些情况下会起作用,但我相信你会明白为什么 Yii 选择它的方法,因为默认情况下它适用于更多情况。

    【讨论】:

    • 谢谢。我接受你的回答,因为这似乎是合理的。是的,Yii 工作方式 与您描述的方式相同,但 使用 代码过于冗长,我不喜欢。我的方法不是少 OO,然后是 Yii 的 - 唯一的区别是重构与 WebUser 对象从 Controller 获取部分 ACL 服务功能。 Yii 和我的代码都在底层使用数组。至于“hallway”的概念,只需使用按位运算,就可以很容易地扩展到随机存取表。我只是暂时不需要它。不过我承认 Yii 的方法更灵活。
    • 关于按位运算的要点。但是,需要注意的是,如果您有一个与多个模型交互的控制器,事情可能会变得复杂。如果您有多个“创建”操作,或者您有一个创建两个模型的操作,该怎么办?或者如果您需要某人有权创建模型,但需要限制该模型上的某个属性,该怎么办。只是需要考虑的事情。你有研究过 Yii 的权利扩展吗?我已经成功地使用了这个:yiiframework.com/extension/rights
    【解决方案2】:

    Yii 通过其 CWebApplication ->authManager 应用程序组件实现了分层 RBAC 方案,这实际上类似于您所做的,

    看看this

    编辑

    "let us suppose that we use RBAC and add some rules into the accessRules method, such as with admin role in the example above." 
    

    当您使用 RBAC 时,您不会将规则添加到 accessRules 方法中

    您所做的是,您定义授权层次结构,包括三个步骤 1)定义授权项目,包括角色和操作, 这将存储在数据库中,在 authitem 表中

    例如。 运营

    siteAddProduct->in this case 'site' is the controller name and addProduct is the action in 'site' controller
    sitedeleteProduct ...etc
    

    角色

    admin,editor...etc
    

    2)建立授权项之间(角色和操作之间)的关系,这将存储在 authitemchild 表中

    例如。

    admin -> siteAddProduct
    editor -> sitedeleteProduct
    admin->editor
    

    3) 为应用程序用户分配角色,这将存储在 authassignment 表中

    例如 用户 ID 1 ->管理员

    现在在您的基本控制器中(假设您有一个控制器类,您的应用程序中的所有其他控制器都从该控制器类扩展) 您覆盖 beforeAction() 方法并使用

    检查登录用户(当前用户)的权限
    Yii::app()->user->checkAccess($operation);
    

    $operation 是请求的控制器 + 动作

    您可以使用 $this->id 获取控制器名称和使用 $this->getAction()->id

    【讨论】:

    • 感谢您的回答。我知道这个。 RBAC 需要运行额外的过程来配置角色并将它们分配给看起来很奇怪的用户,因为相应的数据已经在域模型中可用。我不需要这样的重复。无论如何,让我们假设我们使用 RBAC 并在 accessRules 方法中添加一些规则,例如上面示例中的 admin 角色。问题还是一样:为什么我们需要为当前操作和用户之外的其他操作和用户定义规则?
    • 我知道什么是 RBAC。我刚刚注意到,我们在accessRules 方法中使用了RBAC 中定义的角色,因此添加了涉及角色的访问规则。答案仍然没有回答问题。
    • 如果你已经实现了 RBAC,为什么还要使用 accessRules 方法
    • 我的问题是关于 accessRules 默认实现,而不是关于 RBAC。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多