yiiのアクセス制御を学ぶ CDbAuthManager導入の巻

ロールベースアクセスコントロール(RBAC)を導入するのは面倒で後回しにしてきました。ロールのデザイン、ロール管理の実装、ユーザー管理の実装、権限付与の実装には時間がかかりそうで躊躇してしまうのです。そこでこれらをできる限り省略してRBACを導入することにフォーカスしてみます。

これからやることが想像できない場合はロールベースアクセスコントロールを読む。やりたいことはなんとなくわかった、でもなんだか面倒だなーと思うくらいでOK。とりあえずやってみる。

手順

  1. アプリケーション作成
  2. ユーザー管理
  3. ユーザー認証
  4. 権限付与マネージャの導入
  5. ロール管理
  6. 操作に権限を割り当てる

アプリケーション作成

blogデモを利用します。

  • yii/demo/blogを適当なところにコピー
  • protected/config/main.php にDB設定
  • DBを作成
  • protected/data/schema.mysql.sql とかでスキーマを整える

ユーザー管理

blogデモにはユーザー管理機能がありません。前のポストを参考にしてもいいですが、とりあえずのユーザー生成スクリプトを用意したので使ってください。
4ユーザー usera, userb, userc, userd のパスワードはすべてdemoです。

INSERT INTO tbl_user (id, username, password, salt, email) VALUES (901, 'usera','2e5c7db760a33498023813489cfadc0b','28b206548469ce62182048fd9cf91760','webmaster@example.com');
INSERT INTO tbl_user (id, username, password, salt, email) VALUES (902, 'userb','2e5c7db760a33498023813489cfadc0b','28b206548469ce62182048fd9cf91760','webmaster@example.com');
INSERT INTO tbl_user (id, username, password, salt, email) VALUES (903, 'userc','2e5c7db760a33498023813489cfadc0b','28b206548469ce62182048fd9cf91760','webmaster@example.com');
INSERT INTO tbl_user (id, username, password, salt, email) VALUES (904, 'userd','2e5c7db760a33498023813489cfadc0b','28b206548469ce62182048fd9cf91760','webmaster@example.com');

ユーザー認証

blogデモに実装済みなのでパス。パス。

権限付与マネージャの導入

権限付与マネージャには CDbAuthManager と CPhpAuthManager がありますが今回使うのは前者です。

CDbAuthManager の設定
  • config/main.phpに次を追加する

protected/config/main.php

    'components'=>array(
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'connectionID'=>'db',
        ),
    ),
CDbAuthManager が必要とするテーブルを生成
  • framework/web/auth/schema-*.sql のスクリプトで作成する

ロール管理

yiiガイドにあるロール構造を登録します。権限付与アイテムとは、ロール構造図をあわせて読むと理解しやすい。

権限付与アイテム

権限付与アイテムとは何かをする許可のことです。(例:新しいブログ記事を作る、ユーザを管理する) 粒度と対象者によって、権限付与アイテムはオペレーション、タスク、ロールに分類されます。 ロールは複数のタスクからなり、タスクは複数のオペレーションからなります。 そして、オペレーションが一番小さな許可単位です。

http://www.yiiframework.com/doc/guide/1.1/ja/topics.auth
ロール構造図

ここのロール構造図を参照。

簡易ロール管理

ロール管理はUIで管理したいところですが、今回は SiteController.phpにロールを初期化/登録するアクションを追加します。追加したら http:/path/to/index.php/site/loadroles にアクセスしロール定義をロードします。

protected/controllers/SiteController.php

<?php
    public function actionLoadRoles()
    {
        $auth=Yii::app()->authManager;

        // ロール初期化
        $auth=Yii::app()->clearAll();

        // ロール定義
        $auth->createOperation('createPost','create a post');
        $auth->createOperation('readPost','read a post');
        $auth->createOperation('updatePost','update a post');
        $auth->createOperation('deletePost','delete a post');

        $bizRule='return Yii::app()->user->id==$params["post"]->author_id;';
        $task=$auth->createTask('updateOwnPost','update a post by author himself',$bizRule);
        $task->addChild('updatePost');

        $role=$auth->createRole('reader','reader');
        $role->addChild('readPost');

        $role=$auth->createRole('author','author');
        $role->addChild('reader');
        $role->addChild('createPost');
        $role->addChild('updateOwnPost');

        $role=$auth->createRole('editor','editor');
        $role->addChild('reader');
        $role->addChild('updatePost');

        $role=$auth->createRole('admin','admin');
        $role->addChild('editor');
        $role->addChild('author');
        $role->addChild('deletePost');

        // ユーザーに権限付与
        $auth->assign('reader','1');   //demo
        $auth->assign('reader','901'); //usera
        $auth->assign('author','902'); //userb
        $auth->assign('editor','903'); //userc
        $auth->assign('admin', '904'); //userd
    }

ロール作成時、descriptionを設定しました。

各ユーザーの権限

  • demo 記事の参照
  • usera 記事の参照
  • userb 記事の参照と作成 + 自身が作成した記事の編集
  • userc 記事の参照と作成と編集
  • userd 記事の参照と作成と編集と削除

権限チェック

ここまでできたら次はいよいよユーザーに付与した権限を元にBlogデモが動作するよう改修していきます。ログインユーザーが権限を持っている/いないは CWebUser#checkAccess で得られます。

Yii::app()->user->checkAccess('createPost')

view上で判定する

protected/components/views/userMenu.php

<?php
<ul>
    <?php if (Yii::app()->user->checkAccess('createPost')) : ?>
        <li><?php echo CHtml::link('Create New Post',array('post/create')); ?></li>
    <?php endif; ?>
    <?php if (Yii::app()->user->checkAccess('admin')) : ?>
        <li><?php echo CHtml::link('Manage Posts',array('post/admin')); ?></li>
    <?php endif; ?>
    <?php if (Yii::app()->user->checkAccess('editor')) : ?>
        <li><?php echo CHtml::link('Approve Comments',array('comment/index')) . ' (' . Comment::model()->pendingCommentCount . ')'; ?></li>
    <?php endif; ?>
    <li><?php echo CHtml::link('Logout',array('site/logout')); ?></li>
</ul>
Postコントローラーのアクセスコントロールフィルター

protected/controllers/PostController.php

<?php
    public function accessRules()
    {
        return array(
            array('allow',
                'actions'=>array('index','view'),
                'roles'=>array('readPost'),
            ),
            array('allow',
                'actions'=>array('create'),
                'roles'=>array('createPost'),
            ),
            array('allow',
                'actions'=>array('update'),
                'roles'=>array('updatePost'),
            ),
            array('allow',
                'actions'=>array('delete'),
                'roles'=>array('deletePost'),
            ),
            array('deny',  // deny all users
                'users'=>array('*'),
            ),
        );
    }

まとめ

説明しきれていないことが多々あるけれど、CDbAuthManagerは導入できたと思う。

  • 権限付与マネージャは CDbAuthManager と CPhpAuthManager がある
  • 権限アイテムにはロール、タスク、オペレーションがある。オペレーションが最小単位。
  • ロール管理は権限付与マネージャを使う。が、将来的にはyii-Rightsなどのエクステンションを使って管理すると思う
  • 権限チェックは CwebUser#checkAccess からできる
  • アクセスコントロールフィルターから権限チェックを利用できる