ACLを制御するシンプルなアプリケーション – CakePHP Cookbook v2.x documentation のグループだけのACL に書かれている関数を User モデルに追加すると、ユーザー単位ではなく、グループ単位の ACL とできる、とあります。
しかし、この関数をつけてもつけなくても「 aros テーブルは以下のようになるでしょう」とあるようなテーブル構造になりません。ナンデ?ウェブからユーザーを登録しても、aros テーブルにデータが登録されてしまいます。ナンデ?
そこで、この状態ですこしだけ検証してみましたのでメモします。
検証内容
- グループだけのACL にある関数のあるなしで、任意のページにアクセスしたときに発行される SQL の違いを見ます。
- グループだけのACL にある関数のあるなしで、MySQL に直接 INSERT したユーザーのアクセス権がどうなるか、違いを見ます。
検証するのにそもそも CakePHP でサイトを作る必要がありますが、それは公式ドキュメントのチュートリアルを手順どおりに進めて作成したものを使用しました。つまり、次の2ページをこなしてからのスタートとなります。
- ACLを制御するシンプルなアプリケーション — CakePHP Cookbook v2.x documentation
- ACLを制御するシンプルなアプリケーション – パート2 — CakePHP Cookbook v2.x documentation
グループだけのACL にある関数のあるなしで、任意のページにアクセスしたときに発行される SQL の違いを見ます。
User コントローラーの index アクションにアクセスしたときに発行される SQL で確認しました。URL を一応張っておくと、http://localhost/cakesample4/users となりました。
グループだけのACLじゃない場合は4つ、グループだけのACLの場合は3つの SQL が発行されていました。早速違いありますね!
1つ目
グループだけのACLじゃない場合
SELECT `Aro`.`id`, `Aro`.`parent_id`, `Aro`.`model`, `Aro`.`foreign_key`, `Aro`.`alias` FROM `sampledb4`.`aros` AS `Aro` LEFT JOIN `sampledb4`.`aros` AS `Aro0` ON (`Aro`.`lft` <= `Aro0`.`lft` AND `Aro`.`rght` >= `Aro0`.`rght`) WHERE `Aro0`.`model` = 'User' AND `Aro0`.`foreign_key` = 1 ORDER BY `Aro`.`lft` DESC; +----+-----------+-------+-------------+-------+ | id | parent_id | model | foreign_key | alias | +----+-----------+-------+-------------+-------+ | 4 | 1 | User | 1 | NULL | | 1 | NULL | Group | 1 | NULL | +----+-----------+-------+-------------+-------+
グループだけのACLの場合
SELECT `Aro`.`id`, `Aro`.`parent_id`, `Aro`.`model`, `Aro`.`foreign_key`, `Aro`.`alias` FROM `sampledb4`.`aros` AS `Aro` LEFT JOIN `sampledb4`.`aros` AS `Aro0` ON (`Aro`.`lft` <= `Aro0`.`lft` AND `Aro`.`rght` >= `Aro0`.`rght`) WHERE `Aro0`.`model` = 'Group' AND `Aro0`.`foreign_key` = 1 ORDER BY `Aro`.`lft` DESC; +----+-----------+-------+-------------+-------+ | id | parent_id | model | foreign_key | alias | +----+-----------+-------+-------------+-------+ | 1 | NULL | Group | 1 | NULL | +----+-----------+-------+-------------+-------+
SQL の違いとしては、WHERE 区でした。
- グループだけじゃない → ` Aro0 ` . ` model ` = ‘User’
- グループだけ → ` Aro0 ` . ` model ` = ‘Group’
取得結果の違いは model が User の行がグループだけじゃない、にあることでした。これは大きな違いだと思います。つまり、 model が User の行があることで、ユーザー単位の ACL を有効にしている、そう考えることができます。
2つ目
グループだけのACLじゃない場合も、グループだけのACLの場合も、次のようにまったく同じでした。
SELECT `Aco`.`id`, `Aco`.`parent_id`, `Aco`.`model`, `Aco`.`foreign_key`, `Aco`.`alias` FROM `sampledb4`.`acos` AS `Aco` LEFT JOIN `sampledb4`.`acos` AS `Aco0` ON (`Aco0`.`alias` = 'controllers') LEFT JOIN `sampledb4`.`acos` AS `Aco1` ON (`Aco1`.`lft` > `Aco0`.`lft` AND `Aco1`.`rght` < `Aco0`.`rght` AND `Aco1`.`alias` = 'Users' AND `Aco0`.`id` = `Aco1`.`parent_id`) LEFT JOIN `sampledb4`.`acos` AS `Aco2` ON (`Aco2`.`lft` > `Aco1`.`lft` AND `Aco2`.`rght` < `Aco1`.`rght` AND `Aco2`.`alias` = 'index' AND `Aco1`.`id` = `Aco2`.`parent_id`) WHERE ((`Aco`.`lft` <= `Aco0`.`lft` AND `Aco`.`rght` >= `Aco0`.`rght`) OR (`Aco`.`lft` <= `Aco2`.`lft` AND `Aco`.`rght` >= `Aco2`.`rght`)) ORDER BY `Aco`.`lft` DESC; +----+-----------+-------+-------------+-------------+ | id | parent_id | model | foreign_key | alias | +----+-----------+-------+-------------+-------------+ | 19 | 16 | NULL | NULL | index | | 16 | 1 | NULL | NULL | Users | | 1 | NULL | NULL | NULL | controllers | +----+-----------+-------+-------------+-------------+
3つ目
グループだけのACLじゃない場合
SELECT `Permission`.`id`, `Permission`.`aro_id`, `Permission`.`aco_id`, `Permission`.`_create`, `Permission`.`_read`, `Permission`.`_update`, `Permission`.`_delete`, `Aro`.`id`, `Aro`.`parent_id`, `Aro`.`model`, `Aro`.`foreign_key`, `Aro`.`alias`, `Aro`.`lft`, `Aro`.`rght`, `Aco`.`id`, `Aco`.`parent_id`, `Aco`.`model`, `Aco`.`foreign_key`, `Aco`.`alias`, `Aco`.`lft`, `Aco`.`rght` FROM `sampledb4`.`aros_acos` AS `Permission` LEFT JOIN `sampledb4`.`aros` AS `Aro` ON (`Permission`.`aro_id` = `Aro`.`id`) LEFT JOIN `sampledb4`.`acos` AS `Aco` ON (`Permission`.`aco_id` = `Aco`.`id`) WHERE `Permission`.`aro_id` = 4 AND `Permission`.`aco_id` IN (19, 16, 1) ORDER BY `Aco`.`lft` desc; Empty set (0.00 sec)
グループだけのACLの場合
こちらには対応する SQL はありませんでした。これも大きな違いですが、グループだけじゃない場合で結果が取得できていないので、どういう意味があるのか、よくわかりません。残念。たぶん別のページやユーザーで同じように調べれば何かわかるのかもしれませんが、面倒ですので今はそこまで掘り下げません。
4つ目
こちらもグループだけのACLじゃない場合も、グループだけのACLの場合も、次のようにまったく同じでした。
SELECT `Permission`.`id`, `Permission`.`aro_id`, `Permission`.`aco_id`, `Permission`.`_create`, `Permission`.`_read`, `Permission`.`_update`, `Permission`.`_delete`, `Aro`.`id`, `Aro`.`parent_id`, `Aro`.`model`, `Aro`.`foreign_key`, `Aro`.`alias`, `Aro`.`lft`, `Aro`.`rght`, `Aco`.`id`, `Aco`.`parent_id`, `Aco`.`model`, `Aco`.`foreign_key`, `Aco`.`alias`, `Aco`.`lft`, `Aco`.`rght` FROM `sampledb4`.`aros_acos` AS `Permission` LEFT JOIN `sampledb4`.`aros` AS `Aro` ON (`Permission`.`aro_id` = `Aro`.`id`) LEFT JOIN `sampledb4`.`acos` AS `Aco` ON (`Permission`.`aco_id` = `Aco`.`id`) WHERE `Permission`.`aro_id` = 1 AND `Permission`.`aco_id` IN (19, 16, 1) ORDER BY `Aco`.`lft` desc; +----+--------+--------+---------+-------+---------+---------+------+-----------+-------+-------------+-------+------+------+------+-----------+-------+-------------+-------------+------+------+ | id | aro_id | aco_id | _create | _read | _update | _delete | id | parent_id | model | foreign_key | alias | lft | rght | id | parent_id | model | foreign_key | alias | lft | rght | +----+--------+--------+---------+-------+---------+---------+------+-----------+-------+-------------+-------+------+------+------+-----------+-------+-------------+-------------+------+------+ | 10 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | NULL | Group | 1 | NULL | 1 | 4 | 1 | NULL | NULL | NULL | controllers | 1 | 116 | +----+--------+--------+---------+-------+---------+---------+------+-----------+-------+-------------+-------+------+------+------+-----------+-------+-------------+-------------+------+------+
振り返ると
aros テーブルから取得するデータに model が User の行がある(グループだけのACLじゃない場合)かないかが違いでした。
次の検証に行きましょう。
グループだけのACL にある関数のあるなしで、MySQL に直接 INSERT したユーザーのアクセス権がどうなるか、違いを見ます。
SQL 文で直接 INSERT するユーザーは次のようにしました。
- テーブル → users
- username → inoue
- password → inoue(暗号化したものを INSERT します。暗号化方法は、CakePHP2 認証、Auth コンポーネントのサンプルを世界一シンプルを目指して作ります。 | oki2a24 の★パスワードを自力で作る。を参照ください。)
- group_id → 1
私の場合、SQL 文は次のようになりました。各環境で app/Config/core.php の Security.salt 値が異なるでしょうから、INSERT 文も違うものになります。
INSERT INTO `users` (`id`, `username`, `password`, `group_id`, `created`, `modified`) VALUES (4, 'inoue', '8e6a59da616035715aa7bc4b25bd461b5866549e', 1, NULL, NULL);
これで準備が整いました。
グループだけのACLじゃない場合
- ログイン画面や $this->Auth->allow で許可しているページにはアクセスできました。つまり認証不要のページにはアクセス可能です。
- ログイン後に ACL を設定しているページにアクセスすると、エラーとなりました。
上の1つ目のSQL を発行したときに「そんな行ないよ!」って言われました。無理やり登録した報いですね。インガオホー。
エラーの原文はこれです。「AclNode::node() – Couldn’t find Aro node identified by “Array ( [Aro0.model] => User [Aro0.foreign_key] => 4 ) “」
ちなみに問題となった User [Aro0.foreign_key] => 4 の「4」は users テーブルの id に当たります。
グループだけのACLの場合
- ログイン画面や $this->Auth->allow で許可しているページには、こちらの場合もアクセスできました。
- ログイン後に ACL を設定しているページにアクセスすると、グループだけの ACL の場合は、何の問題もなくアクセスできました。アクセスだけでなく、データの追加、削除も問題なく行えました。
ということで、グループだけの ACL の場合は aros テーブルの model カラムの、すでに登録されている Group だけ見るのでエラーになりません。よって強引にCakePHP の ACL をかませたウェブ以外から登録しても問題が起きません。
データとしては、気持ち悪いですけどね。
終わりに、そもそも
ACL をはじめるにあたり、他の方のやってみたこと、やり方などを参考にさせていただいた中で、こちらのページでも、訝しがっておられたのがきっかけでした。
引用させていただきますと、次のようになります。
パーミッションをグループのみに単純化する
ACLによるAROのチェックをグループのみにします。「app/Model/User.php」に追加
function bindNode($user) {
return array(‘model’ => ‘Group’, ‘foreign_key’ => $user[‘User’][‘group_id’]);
}
※これ追加するだけで出来るらしいけど、なぜかうまくいかないんですよねー。特に問題はないからいいんですが(;´Д`)誰かおしえてください、あーモヤモヤする
こちらのページ、ACL の使い方の勉強に、とても参考にさせていただきました。ありがとうございます。
次の課題としてぱっと思いついたのは、ACL を使用した状態で、一度に多くのユーザーを登録するのに SQL を直に使うことができないのでどうするか?という課題です。これを調べてみるのは面白そうです。
「CakePHP2 ドキュメントの「グループだけのACL」を検証しました♪軽くですけれども。」への2件の返信
同じ疑問でモヤモヤしていたので参考になりました。いろいろ検索した結果、似たような質問&回答らしきものがありましたのでシェアします(間違っていたらコメントごと削除して下さい…)。
■URL
http://stackoverflow.com/questions/4003565/cakephp-acl-how-to-get-group-only-permissions
■回答抜粋
> I assume that in order to realize your solution just remove the acts_as and parent_node declaration in your user model.
# UserモデルのactsAsとparentNodeを消すだけ?
コメントありがとうございます!
ヒントとなりそうなとても有意義なページであると思います。
実際にやってみたいと思います♪