Reglas en rbac

hola, llevo tiempo trabajando con rbac pero aún no lo entiendo del todo, sé que se pueden hacer reglas para los roles y me gustaría que por favor me explicaran cómo.

Tengo las siguientes tablas:


create table `auth_item`

(

`name` varchar(64) not null,

`type` integer not null,

`description` text,

`rule_name` varchar(64),

`data` text,

`created_at` integer,

`updated_at` integer,

primary key (`name`),

foreign key (`rule_name`) references `auth_rule` (`name`) on delete set null on update cascade,

key `type` (`type`)

) engine InnoDB;

En esa tabla auth_item declaro los roles


create table `auth_item_child`

(

`parent` varchar(64) not null,

`child` varchar(64) not null,

primary key (`parent`, `child`),

foreign key (`parent`) references `auth_item` (`name`) on delete cascade on update cascade,

foreign key (`child`) references `auth_item` (`name`) on delete cascade on update cascade

) engine InnoDB;



En esta tabla auth_item_child aplico la herencia, por ejemplo que el usuario admin pueda hacer todo.


create table `auth_assignment`

(

`item_name` varchar(64) not null,

`user_id` varchar(64) not null,

`created_at` integer,

primary key (`item_name`, `user_id`),

foreign key (`item_name`) references `auth_item` (`name`) on delete cascade on update cascade

) engine InnoDB;

En la tabla auth_assignment asigno los roles, de tal forma que tengo un rol admin que hereda crear_post, al asignar admin el usuario podrá crear el post.

Hasta acá todo está casi claro, excepto por el campo data de la tabla auth_item y el uso de la tabla auth_rule, que es la siguiente:


create table `auth_rule`

(

`name` varchar(64) not null,

`data` text,

`created_at` integer,

`updated_at` integer, 

primary key (`name`)

) engine InnoDB;

como ven, existe un campo llamado data tanto en la tabla auth_rule como en la tabla auth_item, las cuales están relacionadas por el campo name.

La cuestión es la siguiente: tengo un blog con muchos usuarios y cada quien tiene su rol, quisiera desde estas tablas poder validar que un usuario solo pueda modificar las noticias que haya creado y no la de otros, intenté poniendo el siguiente código en el campo data sin resultado:


($this->created_by == Yii::$app->user->id) ? true : false

Básicamente retorno verdadero si el campo created_by es igual al usuario logueado o falso de lo contrario.

¿alguien sabe cómo puedo hacer esto? Gracias.

Hay un blog existente programado en Yii 1 http://www.yiiframework.com/extension/yii-blog/, en donde se usa Role based access control (RBAC) para dar acceso a 6 roles diferentes: Guests, Readers, Authors, Editors, Publishers and Admins.

Descárgatelo y mírate el código.

Gracias, ya lo descargué pero no usa el campo bizrule o rulename en este caso, no sé si haya diferencia entre yii1 y yii2. Hasta donde tengo entendido se pueden usar validaciones php pero sigo sin encontrar algo al respecto.

Hola.! disculpa la respuesta tarde, no se si estas usando yii2 pero tu caso es precisamente lo que explican en la guia, yii2 guide autorización y es exactamente lo que quieres hacer, si aun no entiendes esa explicación o ya la leiste, te explico la parte de la regla:

primero una regla (Rule) es una porción de código que debe realizar alguna validación la cual debe retornar un valor booleano que indica si la condición fue cumplida. en tu caso la regla sería (sacada de la guia );


/**

 * Checks if authorID matches user passed via params

 */

class AuthorRule extends Rule

{

    public $name = 'isAuthor';


    /**

 	* @param string|integer $user the user ID.

 	* @param Item $item the role or permission that this rule is associated with

 	* @param array $params parameters passed to ManagerInterface::checkAccess().

 	* @return boolean a value indicating whether the rule permits the role or permission it is associated with.

 	*/

    public function execute($user, $item, $params)

    {

        return isset($params['post']) ? $params['post']->createdBy == $user : false;

    }

}

[color="#000000"]En esta se valida que el valor createBy sea igual al usuario que está intentando realizar la edición, pero ahora cómo usas esto, pues muy fáciĺ, primero debes almacenar el permiso en la base de datos, en este caso el auth_item que relacionarás con la regla creada, en la guia colocan esto :

[/color]


$auth = Yii::$app->authManager;


// add the rule

$rule = new \app\rbac\AuthorRule;

$auth->add($rule);


// add the "updateOwnPost" permission and associate the rule with it.

$updateOwnPost = $auth->createPermission('updateOwnPost');

$updateOwnPost->description = 'Update own post';

$updateOwnPost->ruleName = $rule->name;

$auth->add($updateOwnPost);


// "updateOwnPost" will be used from "updatePost"

$auth->addChild($updateOwnPost, $updatePost);


// allow "author" to update their own posts

$auth->addChild($author, $updateOwnPost);

Con este código, primero estas creando una instancia de la regla que creaste con anterioridad y la estas almacenando en tu tabla auth_rule, luego estas creando un permiso el cual esta relacionado con la regla que has creado.

(es importante decir , y creo que en la guia no lo realizan es que en la base de datos se guarda el objeto serializado en la columna data de la tabla auth_rule por lo tanto cuando se carga de la base de datos se esta usando el objeto que se serializo, lo menciono por cultura general y puede ser útil esta información.)

ahora para que el permiso pueda ser cumplido la regla debe satisfacerse y si examinamos el código de validación del DBmanager podemos observar que si la regla no es cumplida el acceso es denegado y se detiene la propagación de la validación de nuestro esquema de permisos.


protected function checkAccessRecursive($user, $itemName, $params, $assignments)

	{

    	if (($item = $this->getItem($itemName)) === null) {

        	return false;

    	}


    	Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__);

//Aquí

####################################################

    	if (!$this->executeRule($user, $item, $params)) {

        	return false;

    	}

####################################################

    	if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) {

        	return true;

    	}


    	$query = new Query;

    	$parents = $query->select(['parent'])

        	->from($this->itemChildTable)

        	->where(['child' => $itemName])

        	->column($this->db);

    	foreach ($parents as $parent) {

        	if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) {

            	return true;

        	}

    	}


    	return false;

	}

ahora si vemos el metodo que verifica el acceso del DBmanager de yii2 dependiendo si el usuario tiene asignado un determinado item pero ademas podemos observar que si el usuario posee asignada el permiso (En este caso updateOwnPost) pero no satisface la regla indicada en el campo rule_name ( si es null la regla es ignorada. ) el permiso es denegado. esto lo observamos porque en el código primero está la validación de la regla y luego se verifica si el usuario tiene asignado el item.

aquí esta el método executeRule del DBManager de yii2


 /**

 	* Executes the rule associated with the specified auth item.

 	*

 	* If the item does not specify a rule, this method will return true. Otherwise, it will

 	* return the value of [[Rule::execute()]].

 	*

 	* @param string|integer $user the user ID. This should be either an integer or a string representing

 	* the unique identifier of a user. See [[\yii\web\User::id]].

 	* @param Item $item the auth item that needs to execute its rule

 	* @param array $params parameters passed to [[ManagerInterface::checkAccess()]] and will be passed to the rule

 	* @return boolean the return value of [[Rule::execute()]]. If the auth item does not specify a rule, true will be returned.

 	* @throws InvalidConfigException if the auth item has an invalid rule.

 	*/

	protected function executeRule($user, $item, $params)

	{

    	if ($item->ruleName === null) {

        	return true;

    	}

    	$rule = $this->getRule($item->ruleName);

    	if ($rule instanceof Rule) {

        	return $rule->execute($user, $item, $params);

    	} else {

        	throw new InvalidConfigException("Rule not found: {$item->ruleName}");

    	}

	}

podemos observar que si el item no posee ningún rule_name se retorna true, de lo contrario se tratará de ejecutar la regla

indicada en ese campo.

ahora cómo lo utilizas pues puedes hacerlo como lo indican en la guía:


if (\Yii::$app->user->can('updatePost', ['post' => $post])) {

    // update post

}

El método can realiza una llamada al método checkAccess enviandole los parámetros necesarios y se verificará lo que ya escribí XD

bueno espero te ayude la explicación, si todavia tienes una duda o no me expliqué bien, avisame y perdonen la redacción :unsure:

Gracias por la respuesta, estuve probando pero no obtuve éxito, creo que la clave está en implementar algo como esto:


return isset($params['post']) ? $params['post']->createdBy == $user : false;

seguiré investigando a ver qué encuentro.