首页 > 代码库 > Yii rbac原理和实践

Yii rbac原理和实践

  Yii框架中集成分层的 RBAC,代码位于vendor\yiisoft\yii2\rbac中,rbac工作原理分为两部分,建立授权数据和进行权限检查。

技术分享

   如上,一个角色拥有某个权限,如果希望用户拥有这个权限,那么就将拥有该权限的角色赋予给用户,特别是当系统中用户数量非常大的时候,如果需要修改权限只需要修改角色就可以了。

  角色和权限都可以按层次组织。特定情况下,一个角色可能由其他角色或权限构成, 而权限又由其他的权限构成。 一个角色可以包含一个权限,反之则不行。

  特定的权限,可以用一个规则 rule 与一个角色或者权限关联。一个规则用一段代码代表, 规则的执行是在检查一个用户是否满足这个角色或者权限时进行的。例如,"改帖" 的权限 可以使用一个检查该用户是否是帖子的创建者的规则。权限检查中,如果该用户 不是帖子创建者,那么他(她)将被认为不具有 "改帖"的权限。

  Yii中rbac的角色权限数据可以通过文件和数据库进行存放,如果是数据库存放角色权限数据,那么需要配置config目录下web.php和console.php中的authManager。下面以建立一个可以进行注册登录发帖的并且用户只可以修改自己文章的系统为例。

第一步:基本配置

              web.php

技术分享

            console.php

技术分享

 

第二步:初始化数据库

命令行中运行yii的migrate命令,需要将yii.bat所在目录添加到系统环境变量中就可以像下面这样执行了。

  技术分享

然后会在数据库中多出四个表,auth_item, auth_rule, auth_item_child, auth_assignment。

                auth_item表

技术分享

存放权限数据,包含各个权限的名字和描述以及关联的规则,具体的字段含义可以参考yii\rbac\Item类:

<?php
namespace yii\rbac;

use yii\base\Object;

/**
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Item extends Object
{
    const TYPE_ROLE = 1;
    const TYPE_PERMISSION = 2;

    /**
     * @var integer the type of the item. This should be either [[TYPE_ROLE]] or [[TYPE_PERMISSION]].
     */
    public $type;
    /**
     * @var string the name of the item. This must be globally unique.
     */
    public $name;
    /**
     * @var string the item description
     */
    public $description;
    /**
     * @var string name of the rule associated with this item
     */
    public $ruleName;
    /**
     * @var mixed the additional data associated with this item
     */
    public $data;
    /**
     * @var integer UNIX timestamp representing the item creation time
     */
    public $createdAt;
    /**
     * @var integer UNIX timestamp representing the item updating time
     */
    public $updatedAt;
}

item中的type类型,表示该权限是包含一个权限集合的角色TYPE_ROLE ,还是单独权限TYPE_PERMISSION。auth_item_child就储存了角色和权限的父子关系数据。

  auth_rule表中定义了规则,auth_item_child储存了用户和角色的关系数据。

 

第三部:创建角色和权限

  这里创建基本的角色author和editArticle权限,以及一个规则,规定只有对自己的文章可以有editArticle权限。在@app目录下新建rbac文件夹:

<?php
namespace app\rbac;

use yii\rbac\Rule;

/**
 * Created by PhpStorm.
 * User: mao
 * Date: 2016/10/28
 * Time: 0:22
 */
class AuthorRule extends Rule
{
    public $name = ‘isAuthor‘;

    public function execute($user, $item, $params)
    {
        return isset($params[‘post‘]) ? $params[‘post‘] -> authorId == $user : false;
    }
}

  该规则根据传入的$param数据判断,要修改的文章作者是否是自己。下面进行角色和权限的初始化,新建rbacController控制器,

<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\rbac\AuthorRule;

class RbacController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app -> authManager;

        $rule = new AuthorRule();
        $auth -> add($rule);

        $updateArticle = $auth -> createPermission(‘updateArticle‘);
        $updateArticle -> description = ‘更新自己文章‘;
        $updateArticle -> ruleName = $rule -> name;
        $auth -> add($updateArticle);

        $author = $auth -> createRole(‘author‘);
        $auth -> add($author);
        $auth -> addChild($author, $updateArticle);
    }
}

  访问,http://localhost/?r=rbac/init,后数据库中会生产相应的权限角色数据。

技术分享

其中,rule中data是被序列化后的对象。

技术分享

反序列化后如下,

技术分享

保存了rule的基本信息,权限创建好了,需要给每一个注册的用户赋予author权限,具体的注册和发表文章可以自己实现,下面贴一下注册时授予权限的代码:

    public function actionRegister()
    {
        $member = new Member([‘scenario‘ => ‘register‘]);
        $post = Yii::$app -> request -> post();
        if(isset($post[‘Member‘]))
        {
            $exist = Member::findIdentityByUsername($post[‘Member‘][‘username‘]);
            if(!$exist && $member -> load($post) && $member -> setPassword() && $member -> save())
            {
                $auth = Yii::$app -> authManager;
                $author = $auth -> getRole(‘author‘);
                $auth -> assign($author, $member -> id);
                Yii::$app -> user -> login($member);
                return $this -> goHome();
            }
        }

        return $this -> render("register", [‘model‘ => $member]);
    }

用户注册后通过getRole获得角色,然后赋予给用户。下面就是当用户修改文章的时候,根据角色和权限进行判断是否有权限修改。可以通过yii::$app -> user的can方法来进行验证。

    public function actionEdit()
    {
        $articleId = Yii::$app -> request -> get("id");
        $article = Article::findOne([‘id‘ => $articleId]);
        if($article){
            //鉴定是否拥有updateArticle权限
            if(Yii::$app -> user -> can(‘updateArticle‘, [‘post‘ => $article])){
                return $this -> render(‘edit‘, [‘article‘ => $article]);
            }
            return $this -> render(‘noAuth‘);
        }else{
            return $this -> redirect(‘/?r=article/articles‘);
        }
    }

其中,第二个参数就是以后会传给AuthorRule中的execute方法的最后一个参数,这里传入的是article的ActiveRecord对象。

当我们对别人的文章点击编辑后会跳转到你没有权限的提示页面,而自己的文章可以正常修改。

技术分享

 

 提示没有权限。

参考:

http://www.yiichina.com/doc/guide/2.0/security-authorization

http://en.wikipedia.org/wiki/Role-based_access_control

 

Yii rbac原理和实践