ACL PluginでACL再入門

CakePHP Advent Calendar 2012 18日目の記事です。
昨日は、@msngさんのCakePHP の Configure クラスで最も悩ましい点を解決する方法 でした。確かにConfigureはちと長いですよね(^^;。

当初、BDD Pluginについて何か書こうと思っていたのですが、なかなか時間が取れず記事に出来るほどネタがたまっていないので、ストックしてあったネタからACL Pluginについて書きたいと思います。ACLに関しては、@ootatterさんの7日目の記事、ACL.phpとACL.iniについてでも取り上げられていますのであわせて読むと良いかと思います。

ACLは難しい

ACL難しい」という話は結構良く聞きますし、実際僕もそう思っていました。今まではあまり細かな権限管理を要求される事も無かった事もあって、ACLは使わずに簡易的な権限管理機能を自作していました。先日たまたまACL Plugin 2.2.0がリリースされているのを発見したので、今後の為にと試用してみました。実際試してみると、「難しい」というより「少し面倒」といった程度な感じでした。一度使い始めると本当に手放せない機能だと実感してます。ただ、実際に使うには結構準備が大変なので、簡単にACL Pluginを手元の環境で体験できるサンプルを作りました。

GitHub - ACL Plugin Sample

以下で実際の設置方法や注意点等を紹介します。

ACL Plugin sampleの設定

1. サンプルプロジェクトの配置
設置したいディレクトリで以下の手順で、サンプルプロジェクトを配置します。

$ git clone https://github.com/kaz29/acl_plugin_sample.git
$ cd acl_plugin_sample
$ chmod -R go+w ./app/tmp
$ cp ./app/Config/database.php.default ./app/Config/database.php
$ vim ./app/Config/database.php => データベースの設定

2. サンプル用テーブルの作成
以下の様な手順で、サンプルで使用するテーブルを作成します。私はPostgreSQL使いなので以下はPostgreSQLの例ですが、MySQL用のファイルも"schema_mysql.sql" という名前で用意してありますので、適宜読み替えてください。

$ psql データベース名 < ./app/Config/Schema/schema_postgres.sql

今回使用するテーブルは以下の2つです。

テーブル名 モデル名 説明
users User ユーザー情報テーブル(belongsTo:Group)
groups Group 権限情報テーブル(hasMany:User)

3. ACL用テーブルの作成
ACLで利用するテーブルはSchemaファイルが用意されているので以下の様に作成します。

$ ./app/Console/cake schema create DbAcl

ACL Plugin sampleを試す

設定が終わったら、http://localhost/admin/にアクセスしてみましょう。

1. ユーザーの作成

ユーザーが存在しない状態でアクセスをすると、ユーザー作成画面に遷移するのでユーザーを作成します。この時点でグループが存在しない場合、「サイト管理者」と「一般ユーザー」の2つのグループが自動的に作成されます。

2. ログイン

ユーザー作成が完了すると、ログインページに遷移するので先ほど作成したアカウントでログインします。

3. ACO(Access Control Object)の初期化(*1)

ログイン後、acosテーブルにデータが存在しない場合、ACL Pluginのaco同期処理(/admin/acl/acos/synchronize)に遷移します。現在定義されているコントローラ/アクションとacosテーブルの内容をチェックし、存在しない項目がリストアップされます。

画面の下の方にある"Synchronize"をクリックし、acoを作成します。

4. アクセス権限(ARO)の設定

次に、アクセス権限の設定をします。画面上の"Permissions" => "Roles permissions"をクリックしグループ毎の権限設定画面を表示します。

初期状態ではアクセス権限が設定されていないので、サイト管理者の横にある緑のチェックマークをクリックし、サイト管理者にすべての機能へのアクセス権を与えます。

設定が完了すると以下の様に、すべてのアクションへのアクセス権限が付与された事が分かります。

ACLが正常に機能しているかを確認する為に、Groups->admin_indexへのアクセス権を削除してみましょう。下記の画像の赤丸の部分をクリックします。

処理が完了すると、以下の様に表示が切り替わります。

5. 権限が無い機能にアクセスしてみる

この状態で、http://localhost/admin/groups/ にアクセスすると権限が無いため以下の様にエラーが表示されます。

ACL Pluginを使うととても簡単に権限の管理が可能です。グループ単位の設定の他、ユーザー毎にアクセスを許可したり、拒否したりといった事も簡単に出来ますので色々と試してみてください。

実際のカスタマイズ内容はGitHubのCommitログを見ていただければ参考になるかと思います。幾つかコメントも書いておいたので、気づいた点等あれば適宜追記していただければと思います。

ACL Plugin を使う上でのちょっとした注意点

adminルーティングの利用が必須

ACL Pluginはadminルーティングを利用する事を前提に実装されています。URL構造を検討する際には考慮しておきましょう。

Group,User共にモデル経由で作成する必要がある

ACLに関連するデータは、ACLビヘイビアが自動的に生成等の処理を行います。Group,Userのテーブルデータを作成しただけではエラーが発生して正常に動作しません。特に初期状態を作成する際には注意が必要かもしれません。

(*1)user_id:1は特権ユーザー

上の「ACL Plugin sampleを試す」の「ACO(Access Control Object)の初期化」で、まだアクセス権限が設定されていないのに、Acl関連のコントローラーにアクセスできるのを不思議に思った方もいるのではないでしょうか?ACL Pluginではデフォルトでuser_id=1のユーザーが特権ユーザーとして設定されています。下記の'acl.role.access_plugin_user_ids'に設定されているユーザーIDは特権ユーザーとして扱われ、ACLの設定がされていなくてもAcl関連のコントローラにアクセス出来ます。また、'acl.role.access_plugin_role_ids'にグループIDを設定すると設定したグループに所属するユーザーに特権が与えられます。

Acl/Config/bootstrap.php 47行目〜
<?php
...
/*
 * You can add here role id(s) that are always allowed to access the ACL plugin (by bypassing the ACL check)
 * (This may prevent a user from being rejected from the ACL plugin after a ACL permission update)
 */
Configure :: write('acl.role.access_plugin_role_ids', array());

/*
 * You can add here users id(s) that are always allowed to access the ACL plugin (by bypassing the ACL check)
 * (This may prevent a user from being rejected from the ACL plugin after a ACL permission update)
 */
Configure :: write('acl.role.access_plugin_user_ids', array(1));

まとめ

如何でしたでしょうか?ACL Pluginを使う事でかなり簡単にACLを利用出来る事がお分かりいただけたかと思います。是非一度試してみてください。

明日は、@konsanの「Chosen + Search + Collectionableの3つのプラグインの組み合わせ」です。楽しみ!

おまけ

ACL Plugin 2.2.0 の potファイルには漏れがある

ACL Plugin 2.2.0に付属のacl.potには一部の文言が含まれていないため、日本語化したい場合は注意が必要です。i18nコマンドを使って再抽出するか、手動で追加する必要があります。

Authコンポーネントのflashメッセージをカスタマイズ

これは私が実際に困って調べたのですが、TwitterBootstrapPlugin等を使用してデザインをカスタマイズしている場合Authプラグイン内で生成されるflashメッセージが表示されないという問題がありました。こんな場合には以下の様にAuthコンポーネントに設定をする事でカスタマイズ出来ました。

<?php
class AppController extends Controller {
	public $components = array(
            'Acl',
            'Auth' => array(
                .....
                'flash' => array(
                    'element' => 'alert',
                    'params' => array(
                        'plugin' => 'TwitterBootstrap',
                        'class' => 'alert-error'
                    ),
                    'key' => 'flash',
                ),
            ),
....
        );
....
}