ACLコンポーネントによるアクセス制御

更新日 2022-02-19 20:30:48
cakephp3

Aclプラグインのインストールと設定

Aclプラグインのインストール

composer require cakephp/acl:dev-master
config/bootstrap.phpに以下を記述する

\App\Application::addPlugin('Acl',['bootstrap' => true]);
Acl用のテーブルを作成

// aros、acos、aros_acosの3テーブルを作成
bin/cake migrations migrate -p Acl

各ファイルの設定

AppController.php

namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
use Cake\Controller\ComponentRegistry;
use Acl\Controller\Component\AclComponent;

class AppController extends Controller
{
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Flash');
        $this->loadComponent('Acl.Acl');
        $this->loadComponent('Auth', [
            'loginAction' => [
                'prefix' => false,
                'controller' => 'Users',
                'action' => 'login',
            ],
            'loginRedirect' => [
                'prefix' => false,
                'controller' => 'Pages',
                'action' => 'display',
                'home',
            ],
            'logoutRedirect' => [
                'prefix' => false,
                'controller' => 'Users',
                'action' => 'login',
            ],
            // 認証の種類
           'authenticate' => [
                'Ldap',
                'Form' => [
                    'fields' => [
                        'username' => 'username',
                        'password' => 'password',
                    ]
                ]
            ],
            // 権限チェックの方法
            'authorize' => [
                // Acl認証 => isAuthorizedメソッド不要
                'Acl.Actions' => ['actionPath' => 'controllers/'],
                // カスタム認証 => isAuthorizedメソッドを使う場合
                'Controller',
            ],
        ]);
    }

    // ※有効にするには'authorize' => ['Controller'] に設定する
    public function isAuthorized($user)
    {
        $Collection = new ComponentRegistry();
        $acl = new AclComponent($Collection);
        $controller = $this->request->controller;
        $action     = $this->request->action;
        return $acl->check(['Users' => ['id' => $user['id']]], "$controller/$action");
    }
}
GroupsTable.php

class GroupsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('groups');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');

        $this->addBehavior('Timestamp');
        $this->addBehavior('Acl.Acl', ['type' => 'requester']); // 追加

        $this->hasMany('Users', [
            'foreignKey' => 'group_id',
        ]);
    }
}
UsersTable.php

   public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('users');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->addBehavior('Timestamp');
        $this->addBehavior('Acl.Acl', ['type' => 'requester']); // 追加

        $this->belongsTo('Groups', [
            'foreignKey' => 'group_id',
            'joinType' => 'INNER',
        ]);
    }

Group.php

class Group extends Entity
{
    public function parentNode()
    {
        return null;
    }

}
User.php

class User extends Entity
{
    public function parentNode()
    {
        if (!$this->id) {
            return null;
        }
        if (isset($this->group_id)) {
            $group_id = $this->group_id;
        } else {
            $users_table = TableRegistry::getTableLocator()->get('Users');
            $user = $users_table->find('all', ['fields' => ['group_id']])->where(['id' => $this->id])->first();
            $group_id = $user->group_id;
        }
        if (!$group_id) {
            return null;
        }
        return ['Groups' => ['id' => $group_id]];
    }

}

権限設定

Aros作成
Group追加、User追加をおこなうことによりarosが作成される

acos作成

// コマンドを実行して一括作成
bin/cake acl_extras aco_sync
// (新しくControllerやActionを追加した場合は下記のコマンドで更新する)
bin/cake acl_extras aco_update
パーミッションの設定例

bin/cake acl grant Groups.1 controllers
bin/cake acl deny Groups.2 controllers
bin/cake acl grant Groups.2 controllers/Posts
bin/cake acl grant Groups.2 controllers/Widgets
bin/cake acl deny Groups.3 controllers
bin/cake acl grant Groups.3 controllers/Posts/index
bin/cake acl grant Groups.3 controllers/Posts/view
bin/cake acl grant Groups.3 controllers/Widgets/index
bin/cake acl grant Groups.3 controllers/Widgets/view
任意に権限チェックをする方法 AppControllerのisAuthorizedを呼ぶ

// コントローラーのアクション内
$user = $this->request->getSession()->read('Auth.User');
$flag = $this->isAuthorized($user);
※Helperにメソッドを作成してもOK。ちなみに$userは配列でもエンティティでも大丈夫みたい。