Yii RBAC: access to specific items/rows

懵懂的女人 提交于 2019-12-06 07:58:11

I wrote a small framework for access control. It is simple, small and light. My motivation was to decouple the access control of my applications from other frameworks, because I think the access control from others frameworks very coupled to framework style.

For instance in Yii where you have to program it in the controller, and I don't like it, because is very boring program new rules when you add a new action(from Yii Wiki):

class PostController extends CController
{

    public function accessRules()
    {
        return array(
            array('deny',
                'actions' => array('create', 'edit'),
                'users' => array('?'),
            ),
            array('allow',
                'actions' => array('delete'),
                'roles' => array('admin'),
            ),
            array('deny',
                'actions' => array('delete'),
                'users' => array('*'),
            ),
        );
    }

}

IMHO, it must be done dynamically. You should be able to program the rule in its administrative system visually and then the developer program an action and a model appropriately and then is ready.

To integrate my library with Yii applications I use import, for example:

$path = Yii::getPathOfAlias('application.services.RapidAuthorization');
Yii::setPathOfAlias('RapidAuthorization', $path);

And I use beforeControllerAction() from module(s) to integrate.

When I have time I will write a manual integration for multiple frameworks, first with which I have experience as Yii, Zend and Symfony. And translate the documentation to english. But the code is english now.

I hope that at least give you an idea of ​​how to write your access control.

You can make use of Yii's concept of data owner in its access control implementation.

The first step to implementing this in your own application is to instruct the controller to enable this rule. This is done by overwriting the filters() function.

class ContentController extends Controller {

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

    public function accessRules() {
    }
}

The 'accessControl' flag specifies that access control is applied for data management. The actual business rules are defined in the accessRules() function, and specifying the access control expression that will be evaluated to provide the desired control. And example of the function implementation is.

public function accessRules() {
    return array(
        array('allow', // allow all users to perform 'index' and 'view' actions
            'actions' => array('view'),
            'users' => array('*'),
        ),
        array('allow', // allow authenticated user to perform 'add' action
            'actions' => array('add'),
            'users' => array('@'),
        ),
        array('allow', // allow only the owner to perform 'modify' 'delete' actions
            'actions' => array('modify', 'delete'),
            'expression' => array('ContentController','isMyRecord')
        ),
        array('deny', // deny all users
            'users' => array('*'),
        ),
    );
}

The isMyRecord is a method that will be run that returns true or false to indicate if the action should be allowed.

public function isMyRecord(){

    if (Yii::app()->user->checkAccess( ...))
       return true;
    else
       return false;
}

I decided to take the following approach, after deciding that simply maintaining an array of Company Items inside $data['companyItemsAllowed'] was not the best for these requirements:

  • created an association table between Users and CompanyItems; call it association_table;
  • created the RBAC tree as shown in the question, but where the bizRule was something like the following:

    $ret = Yii::app()->dbConnection->createCommand('SELECT EXISTS(SELECT 1 FROM `association_table` WHERE user_id=:userId AND company_item_id=:companyItemId)')
    ->queryScalar(array(':userId' => $params['userId'], 'companyItemId' => $params['companyItemId']));
    return $ret;
    

This allows me to maintain the access control interface, like so:

    Yii::app()->user->checkAccess('editItem', array('companyItemId' => 666));

(recall that we do not need to pass on userId on the $params array!.)

Of course, this separates the actual assigning of permissions to Company Items from the RBAC system: I assign editCompanyItemRole to some user using the RBAC mechanisms offered by Yii, but each actual item must be assigned individually by inserting a row onto association_table...

So, although first thought about maintaining an array of Company Items inside $data would probably work, I think this is best and more flexible. Also, the general idea about the bizRule seems to work.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!