dql7588 2013-01-09 16:04
浏览 62
已采纳

Yii的accessRules误解

I'm trying to build a site using Yii, and found myself in a situation which requires some clarifications on access control metaphor in Yii. Specifically, one can override accessRules method in CController's descendant.

Prerequisite:

Here is a code generated by default by Gii, much similar to the 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('*'),
        ),
    );
}

The Question:

What is not clear here to me, is -- why we need to define access rules for many different users and groups, and different actions instead of checking rights of only one current user and action? -- here in italics my main question is highlighted, just in case it may not so clear for readers (answer authors).

This code is executed in a context of specific request, for which a specific controller, a specific action, and a specific user are already known. If, for example, the user is a guest, I don't see any reason to define rules for "admin" role or authenticated users.

Reasoning:

After some elaboration I came up to the following implementation:

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

where hasRights is a simple custom method added into a CWebUser descendant:

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]);
  }
}

As you may see, hasRights uses current user "rights" (read from DB as usual), current controller and action to calculate single boolean true or false value as a decision about access.

What is wrong with this approach? Why Yii does not use something simple like that by default?

The Gii-generated accessRules above do not only look excessive, but also imply that access rules are scattered among many controllers. In my approach a single and compact ACL is used.

  • 写回答

2条回答 默认 最新

  • duande3134 2013-08-02 22:32
    关注

    Here's where I think you're confused.

    First of all, Yii is in fact only looking at the current user and the current action. Just like how you got the current permissions for the controller by grabbing a nested array, indexed by the controller ID, Yii is creating an instance of your controller and only looking at those access rules. Also, just like you're only looking at the permissions of a particular action, Yii is only looking at the rules pertaining to the current action. It accesses those permissions just as easily as you return the value of the nested array.

    As far as the user goes, it's also only looking at the current user; the current user name, the current user role, etc. The difference is, there are multiple attributes Yii will allow within a rule, in contrast to the single permission value associated with the user.

    It seems what you don't like about this approach is you think permissions should be handled all in one place. This could be simpler in some cases, but more difficult in others. What happens when you have multiple controllers and multiple actions in each controller? You now have a very large array to manage, that references data from multiple different contexts. In the way Yii does it, the current controller has control over how it's data structure can be accessed. This lines up with Yii's MVC structure, and the concept of encapsulation.

    Your solution is more elegant in some respects, but it hinges on the idea that permissions will only ever need to be structured in a cascading one directional structure. What I mean is your permissions are like one long hallway, with doors separating one area from another. If the user doesn't have the key to one door, they shouldn't be able to access the next, etc. But what happens if, in your example, you need a user to both view content, and update it without being able to create new content? This is a much more complicated scenario which will need to be handled using roles. So then you'd have to process rules within your array, much like Yii does. Except instead of Yii's object oriented approach, you've got everything embedded in one long array.

    So perhaps your solution will work in some cases, but I'm sure you can see why Yii chose its approach since it will work, by default, for far more situations.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办