Yii的accessRules误解

时间:2013-01-09 16:04:42

标签: php access-control yii

我正在尝试使用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已知 。例如,如果用户是访客,我认为没有理由为“admin”角色或经过身份验证的用户定义规则。

推理:

经过一番阐述后,我得出了以下实施方案:

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。

2 个答案:

答案 0 :(得分:3)

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

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

就用户而言,它也只是关注当前用户;当前用户名,当前用户角色等。区别在于,与用户关联的单个权限值相比,Yii在规则中允许多个属性。

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

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

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

答案 1 :(得分:0)

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)定义授权itmes,包括角色和操作, 这将存储在DB,authitem表中

EG。 运营

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)为应用程序用户分配角色,这将存储在自动分配表

中 例如,

用户ID 1 - >管理员

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

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

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

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