CakePHPでACLを導入する。
Webサービスを企画した時に、各ユーザー個別にサービスの提供を考えるケースがほぼ大半を占めると思います。(少なくても私の企画環境はそんな感じです)
なので、CakePHPで、それぞれのユーザに応じて各種機能にアクセス権を設定するためのコンポーネント、「ACL – アクセス制御リスト(Access Control List)」の導入です。
参考サイト
ACLを制御するシンプルなアプリケーション — CakePHP Cookbook v2.x documentation.
CakePHP2でACLが超簡単に管理できるプラグイン「Alaxos – Plugin ACL 2.0」まとめ – 高橋です.
CakePHP ACL – アクセス制御リストを攻略する | hijiriworld Web.
CakePHPで行うアクセス制御
Authコンポーネントは、ユーザ認証を実現する非常にシンプルで簡単なコンポーネントですが、あくまでも「そのユーザがログインしているか否か」ということのみです。
それぞれのユーザに応じて各種機能にアクセス権を設定するためのコンポーネント、それが「ACL – アクセス制御リスト(Access Control List)」です。
なので、ウェブサービスで、それぞれの訪問ユーザーのレベルに応じた動きをサイトにさせるためには、どうやら必修の機能のようです。頑張って設定してみましょう。
開発中のシステムと混じってしまうのもなんですし、ここは新規なcakePHPの環境を用意します。 CakePHP2.2.2 CakePHP2.2.5 CakePHP2.3.1で動作を確認しました。
データベースの設定
まずは、ユーザーとグループのテーブルを作ります。
CREATE TABLE users ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(255) NOT NULL UNIQUE, password CHAR(40) NOT NULL, group_id INT(11) NOT NULL, created DATETIME, modified DATETIME ) DEFAULT CHARSET=utf8; CREATE TABLE groups ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, created DATETIME, modified DATETIME ) DEFAULT CHARSET=utf8;
次に、app/Config/Schema/db_acl.sqlのテーブル作成します。
CREATE TABLE acos ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, parent_id INTEGER(10) DEFAULT NULL, model VARCHAR(255) DEFAULT '', foreign_key INTEGER(10) UNSIGNED DEFAULT NULL, alias VARCHAR(255) DEFAULT '', lft INTEGER(10) DEFAULT NULL, rght INTEGER(10) DEFAULT NULL, PRIMARY KEY (id) ) DEFAULT CHARSET=utf8; CREATE TABLE aros_acos ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, aro_id INTEGER(10) UNSIGNED NOT NULL, aco_id INTEGER(10) UNSIGNED NOT NULL, _create CHAR(2) NOT NULL DEFAULT 0, _read CHAR(2) NOT NULL DEFAULT 0, _update CHAR(2) NOT NULL DEFAULT 0, _delete CHAR(2) NOT NULL DEFAULT 0, PRIMARY KEY(id) ) DEFAULT CHARSET=utf8; CREATE TABLE aros ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, parent_id INTEGER(10) DEFAULT NULL, model VARCHAR(255) DEFAULT '', foreign_key INTEGER(10) UNSIGNED DEFAULT NULL, alias VARCHAR(255) DEFAULT '', lft INTEGER(10) DEFAULT NULL, rght INTEGER(10) DEFAULT NULL, PRIMARY KEY (id) ) DEFAULT CHARSET=utf8;
DEFAULT CHARSET=utf8 は、2バイト圏のおまじないです。
cake bake します
CakePHPのディレクトリまで降りて、
$cd /path/to/cakephp/ $sudo ./app/Console/cake bake
Welcome to CakePHP v2.2.5 Console --------------------------------------------------------------- App : app Path: /Users/gworks/Sites-Folder/cakephp_acl/app/ --------------------------------------------------------------- Interactive Bake Shell --------------------------------------------------------------- [D]atabase Configuration [M]odel [V]iew [C]ontroller [P]roject [F]ixture [T]est case [Q]uit What would you like to Bake? (D/M/V/C/P/F/T/Q) > m --------------------------------------------------------------- Bake Model Path: /Users/gworks/Sites-Folder/cakephp_acl/app/Model/ --------------------------------------------------------------- Use Database Config: (default/test) [default] > Possible Models based on your current database: 1. Aco 2. Aro 3. ArosAco 4. Group 5. User Enter a number from the list above, type in the name of another model, or 'q' to exit [q] > 5 A displayField could not be automatically detected would you like to choose one? (y/n) > n Would you like to supply validation criteria for the fields in your model? (y/n) [y] > n Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n) [y] > y One moment while the associations are detected. --------------------------------------------------------------- Please confirm the following associations: --------------------------------------------------------------- User belongsTo Group? (y/n) [y] > Would you like to define some additional model associations? (y/n) [n] > --------------------------------------------------------------- The following Model will be created: --------------------------------------------------------------- Name: User DB Table: `cakephp_acl`.`users` Associations: User belongsTo Group --------------------------------------------------------------- Look okay? (y/n) [y] > Baking model class for User... File `/Users/gworks/Sites-Folder/cakephp_acl/app/Model/User.php` exists Do you want to overwrite? (y/n/q) [n] > y Wrote `/Users/gworks/Sites-Folder/cakephp_acl/app/Model/User.php` PHPUnit is not installed. Do you want to bake unit test files anyway? (y/n) [y] > n --------------------------------------------------------------- Interactive Bake Shell --------------------------------------------------------------- [D]atabase Configuration [M]odel [V]iew [C]ontroller [P]roject [F]ixture [T]est case [Q]uit What would you like to Bake? (D/M/V/C/P/F/T/Q) > m --------------------------------------------------------------- Bake Model Path: /Users/gworks/Sites-Folder/cakephp_acl/app/Model/ --------------------------------------------------------------- Possible Models based on your current database: 1. Aco 2. Aro 3. ArosAco 4. Group 5. User Enter a number from the list above, type in the name of another model, or 'q' to exit [q] > 4 Would you like to supply validation criteria for the fields in your model? (y/n) [y] > n Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n) [y] > One moment while the associations are detected. --------------------------------------------------------------- Please confirm the following associations: --------------------------------------------------------------- Group hasMany User? (y/n) [y] > Would you like to define some additional model associations? (y/n) [n] > --------------------------------------------------------------- The following Model will be created: --------------------------------------------------------------- Name: Group DB Table: `cakephp_acl`.`groups` Associations: Group hasMany User --------------------------------------------------------------- Look okay? (y/n) [y] > Baking model class for Group... File `/Users/gworks/Sites-Folder/cakephp_acl/app/Model/Group.php` exists Do you want to overwrite? (y/n/q) [n] > y Wrote `/Users/gworks/Sites-Folder/cakephp_acl/app/Model/Group.php` PHPUnit is not installed. Do you want to bake unit test files anyway? (y/n) [y] > n --------------------------------------------------------------- Interactive Bake Shell --------------------------------------------------------------- [D]atabase Configuration [M]odel [V]iew [C]ontroller [P]roject [F]ixture [T]est case [Q]uit What would you like to Bake? (D/M/V/C/P/F/T/Q) > q
という感じで、groupとuserについてmodel,controller,viewをbakeします。
リクエスタとして振舞う
モデル中で parentNode() を定義します。こうすることで、AclBehavior でモデルとACLテーブルを自動的に結びつけることができます。
User.php
class User extends AppModel { public $name = 'User'; public $belongsTo = array('Group'); public $actsAs = array('Acl' => array('type' => 'requester')); public function parentNode() { if (!$this->id && empty($this->data)) { return null; } if (isset($this->data['User']['group_id'])) { $groupId = $this->data['User']['group_id']; } else { $groupId = $this->field('group_id'); } if (!$groupId) { return null; } else { return array('Group' => array('id' => $groupId)); } } }
Group.php
class Group extends AppModel { public $actsAs = array('Acl' => array('type' => 'requester')); public function parentNode() { return null; } }
このコードで、 Group モデルと User モデルをACLに結びつけ、 User や Group をデータベースに登録した時、常にCakePHPが aros にも同様の登録を行うようにしています。 これにより、 users および groups テーブルをAROと透過的に結びつけるACLの管理機能を、アプリケーションの一部として作成できました。 ユーザーやグループを作成したり削除すると、常に ARO のテーブルも更新されます。
グループとユーザを追加
http://localhost/cakephp_acl/groupsにアクセスします。
bakeしたので、できている画面で、追加ができます。groups/add からグループを追加してみます。
- administrators
- managers
- users
を追加しました。
ユーザーとグループを追加すると、aros
テーブルに自動で値が追加されていれば、ここまでは成功です。
プラグイン「Plugin ACL」の導入
ACL Plugin for CakePHP 2.0 からプラグインをダウンロードします。
解凍してできたフォルダ acl を /app/plugins に保存します。
app/plugins/acl/config/bootstrap.phpのデフォルトグループがRoleなのでGroupに変更します。
Configure :: write('acl.aro.role.model', 'Group');
Configure :: write('acl.aro.role.foreign_key', 'group_id');
/app/Config/core.php の admin root を有効にします。
Configure::write('Routing.prefixes', array('admin'));
/app/Config/bootstrap.php に ACLプラグインのbootstrapを読みこませる指示を追加します。
CakePlugin::load('Acl', array('bootstrap' => true));
AppController.php の追加
bakeしたAppController.phpに以下を追加しておきます。
class AppController extends Controller { public $components = array( 'Acl', 'Auth' => array( 'authorize' => array( 'Actions' => array('actionPath' => 'controllers') ) ), 'Session' ); public $helpers = array('Html', 'Form', 'Session'); function beforeFilter() { // Allow all actions. CakePHP 2.0 $this->Auth->allow('*'); // Allow all actions. CakePHP 2.1 $this->Auth->allow(); //AuthComponentの設定 $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login'); $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login'); $this->Auth->loginRedirect = array('controller' => 'posts', 'action' => 'add'); $this->Auth->actionPath = 'controllers/'; } }
いよいよ起動です。
/admin/acl にアクセスします。
こんなかんじに出てくればOKです。
【Permissions】【 Roles permissions】で、各グループ毎のアクセス設定ができます。
チェックやバツのアイコンをクリックすると切り替わり、アクセス設定が変更できるようになります。
非常に素敵です。
最後に、ログインアクセスを有効にしておきます。
AppController.php
// Allow all actions. CakePHP 2.0 //$this->Auth->allow('*'); // Allow all actions. CakePHP 2.1 //$this->Auth->allow();
これで、きっと少し楽になるはずです。
コメント