CakePHP2.xでACL制御

2ba5fb36e4ea8a2a5c4f33d90482565b_m

Webアプリ開発を行う上では必須の機能といっても過言ではないACL(アクセスコントロールリスト)での制御。でも面倒くさい。
しかももう一度やれと言われても覚えてられないほど作業工程が多い。
ので、備忘録に。

基本的にはcookbookを見ながら対応。
https://book.cakephp.org/2.0/ja/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html
今回は簡単なチャットシステムを構築する予定なので、以下のテーブルを作成。

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,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    sex INT(11) NOT NULL,
    age_id INT(11) NOT NULL,
    address VARCHAR(255) NOT NULL,
    work_id INT(11) NOT NULL,
    img_file VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE groups (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE posts (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    user_id INT(11) NOT NULL,
    title VARCHAR(255) NOT NULL,
    body TEXT,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE widgets (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    part_no VARCHAR(12),
    quantity INT(11)
);

CREATE TABLE questions (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    item VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE answers (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    chois INT(11) NOT NULL,
    question_id INT(11) NOT NULL,
    user_id INT(11) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE chats (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    body TEXT,
    user_id INT(11) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE ages (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    age VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE works (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    kind VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

groups、posts、widgetsはACLで必要らしいテーブル。
もちろんusersも。
その他はチャットシステム用。

次に各テーブルをそれぞれbake。
コマンドプロンプトでappフォルダまでcdし、

Console\cake bake all

で各テーブルをガシガシbake。

ここからはコツコツとカキカキ。
UsersController.phpにログインするためのFunctionを記述。

public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
}
$this->Session->setFlash(__('Your username or password was incorrect.'));
}
}

public function logout() {
}

login.ctpを追加。

<?php
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->inputs(array(
'legend' => __('Login'),
'username',
'password'
));
echo $this->Form->end('Login');
?>

User.phpにパスワードのハッシュ化を追記。

public function beforeSave($options = array()) {
$this->data['User']['password'] = AuthComponent::password(
$this->data['User']['password']
);
return true;
}

サイト全体にACL化を行うためAppController.phpにAuth認証を追記。

public $components = array(
'DebugKit.Toolbar',
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
)
),
'Session'
);
public $helpers = array('Html', 'Form', 'Session');

public function beforeFilter() {
// 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'
);
}

とりあえず、認証がかかると面倒なのでAppController.phpに全体的に認証なしの記述を追記(あとで削除)。

public function beforeFilter() {
$this->Auth->allow();
}

ACL用テーブルを作るためにシェルを実行。
いつも通りappフォルダにcdしてコマンドプロンプトで以下を実行。

Console\cake schema create DbAcl

コマンドプロンプトで聞かれる質問は2つともYを答える。

モデルとACLテーブルを紐づけるためにAclBehaviorを使用。(このへんはよくわからないのでチュートリアル通りにする)

User.phpに以下を追記。
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に以下を追記。

public $actsAs = array('Acl' => array('type' => 'requester'));

public function parentNode() {
return null;
}

次に実際の画面でグループを登録します。
チュートリアルでは3つのグループになっていますが、今回のシステムではユーザーと管理者の2種類でいいので
administrators
users
を登録します。

http://localhost/xxxxx/groups/add
にアクセスし登録。
すると、以下のようなエラー画面が。
SnapCrab_NoName_2017-1-27_16-40-2_No-00

実はエラーを吐き出しているものの、データの登録は無事終了しています。
http://localhost/xxxxx/groups/
で一覧を確認すると、確かに登録されています。
フラッシュメッセージの表示エラーのようで、コントローラーでコンポーネント設定をすれば解消されるとのこと。

初期値ではこうなっている表示を

public $components = array('Paginator');

こう変えればエラーがでません。

public $components = array('Paginator','Flash');

私は各コントローラーごとに入れるのが面倒なので、AppController.phpに設定しました。
bake時に対応してくれると楽なんですけどね。

次に、またまたよくわかりませんがACOなるものの作成が必要です。
ACO(アクセスコントロールオブジェクト)とはアクセスを制御される対象物のことのようです。
まあ、チュートリアル通りにシェルを実行してコントローラーを作成。
いつも通りコマンドプロンプトでaapにcdし以下を実行。

Console\cake acl create aco root controllers

今日はここまで。次回に続く。

コメントを書く