CakePHP 2.x 系で会員認証 / ログイン関係の機能を AuthComponent を使って構築する方法

CakePHP 2.1 でオリジナル CMS を構築する際に管理者やスタッフがログインできるような機能を構築します。この記事に書いてあることを理解すれば大抵の会員登録関係の仕組みは構築できるようになるので、構築をしたことない方は参考にしてみてください。

今回参考になったページは以下となります。

Twitter でも数人の方からアドバイスを頂きました。この場を借りてアドバイスをくださった方々にお礼申し上げます。

初期設定

ログイン関連には Session を使用しますので、この辺りを予め設定しておきます。万が一設定せずに進めると、ログインを実行しても一瞬だけログインに成功しても保持されずに、またログイン画面が出てくると行った状態になって非常に混乱しますので気をつけて下さい。

Session の詳細設定をする

bootstrap.php に以下の記述をするか、core.php に設定を書いている人は core.php の該当する部分を書き換えて下さい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Configure::write('Security', array(
    'level' => 'high',
    'salt' => 'qwertyuiopasdfghjklzxcvbnm',
    'cipherSeed' => '12345678900987654321'
));
Configure::write('Session', array(
    'defaults' => 'database',
    'cookie' => 'SID',
    'timeout' => 259200,
    'ini' => Array(
        'session.cookie_lifetime' => 2580000,
        'session.gc_maxlifetime' => 2580000,
        'session.gc_probability' => 1,
        'session.gc_divisor' => 100
    )
));

この設定では以下のような設定となります。

  • セキュリティレベルは high
  • Session の保存先にデータベースを使用
  • Session のタイムアウトは 259200 * hight (10s)

テスト用になるべく大きめの値を設定していますが、開発しているサイトに合わせてこの時間を変更したり、Session の保存先などもお好みに合わせて変えて下さい。ちなみに私が今まで体験したことだと、Session の保存先を php にしていた所、設定した通りに Session が持続しませんでした。海外のフォーラムのどこかで CakePHP の Session を使用する場合は cake を使うと良いなんて話を見かけたこともあったので、私は cake を使用するようにしています。

Session 用のデータベースを作成する

Session の保存先をデータベースにした場合は、データベースに cake_sessions テーブルを作成しておく必要があります。テーブルの構造は以下のようにします。phpMyAdmin を使用している人は SQL のタブをクリックして以下の SQL をコピーして貼りつけて実行をすればテーブルが作成されます。

1
2
3
4
5
6
CREATE TABLE IF NOT EXISTS `cake_sessions` (
  `id` varchar(255) NOT NULL DEFAULT '',
  `data` text NOT NULL,
  `expires` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

これらの設定は以下で以前まとめたものとなります。

追記: User テーブルを作成する

ユーザーテーブルを忘れておりましたので追記となりますが掲載させて頂きます。最後のログイン時間などを取得したい場合は updated カラムを設定しても良いです。今回は管理者アカウントですので、ログインではなくデータの作成時間や更新時間があれば十分だと思いますので created のみとしています。

1
2
3
4
5
6
7
8
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(120) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `role` varchar(20) NOT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

コントローラー / モデル / ビューを作る

初期設定が終われば次は実際にコードを書いていきます。

コントローラー

今回は管理画面ということなので AdminContoroller という名前で作成します。このコントローラーは管理画面用にあらゆる設定が既にしてあります。一番の注意点として $this->Auth->allow() で add アクションを許可していますが、これはテスト用で、もし本番で同じような仕組みを作成する場合は add は許可しないようにしてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class AdminController extends AppController
{
    public
        $uses = Array('User'),
        $components = Array(
            'Session',
            'Auth' => Array(
                'loginRedirect' => Array('controller'  => 'admin', 'action' => 'index'),
                'logoutRedirect' => Array('controller' => 'admin', 'action' => 'login'),
                'loginAction' => Array('controller' => 'admin', 'action' => 'login'),
                'authenticate' => Array('Form' => Array('fields' => Array('username' => 'email')))
            )
        );
 
    public function beforeFilter()
    {
        parent::beforeFilter();
        $this->layout = 'admin';
        $this->Auth->allow('add', 'login');
    }
 
    public function index()
    {
        $this->set('title_for_layout', 'ダッシュボード | 管理画面');
    }
 
    public function login() {
        if($this->request->is('post')) {
            if($this->Auth->login()) {
                return $this->redirect($this->Auth->redirect());
            } else {
                $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
            }
        }
    }
 
    public function logout($id = null)
    {
        $this->redirect($this->Auth->logout());
    }
 
    public function add() {
        if($this->request->is('post')) {
            $this->User->create();
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved'));
                $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        }
    }
}

各アクションについて下記表で解説します。

アクション / 変数 説明
$this->components いろいろと設定を入れていますが、Auth の中の loginRedirect はログイン後のリダイレクト先、logoutRedirect はログアウト後のリダイレクト先、loginAction はログインしていない場合のリダイレクト先、authenticate は CakePHP のデフォルトの設定をカスタマイズしています。今回のケースではログインにデフォルトの username ではなく email を使うためここで書き換えています。
$this->beforeFilter() お馴染みのコントロール起動時に実行されるメソッドです。この中で $this->layout としているのは管理画面用のレイアウトに私が変えたいからです。テストで管理画面用のレイアウトを作成するのが面倒な場合はこの行を削除すれば良いです。削除しない場合はご自分で View/Layout/admin.ctp を作成してください。
$this->Auth->allow() はログインしていない時に許可するアクションを配列で格納します。今回は add はテスト用に常時開放、login はログインしていない状態でもアクセスする必要があるため開放するため、$this->Auth->allow(‘add’, ‘login’) と記述しています。
$this->login() ログイン用メソッドです。POST 送信時に $this->Auth->login() が送信されたデータからログイン情報を探して実際に会員情報が存在するか調べてくれます。存在すればログイン成功となり、Session に会員情報が記録されてログイン後のリダイレクト先として設定したページへリダイレクトします。失敗時はリダイレクトせずに $this->Session->setFlash でログインフォームにログイン失敗のメッセージを表示します。ログイン情報は $this->Auth->user() で取得できます。
$this->logout() ログアウトを実行します。通常ログアウト処理は POST 送信でワンタイムトークンと共に実装すると、予期せぬログアウトなどが起こらなくてすみます。今回は管理画面である点とサンプルコードであるという点から、マニュアル通りの GET で実装とさせて頂いております。
$this->add() 会員を登録します。今回テストでログインする会員は登録する必要がありますので、こちらのページから登録してください。テスト用のため誰でもアクセスできるようにしています。

モデル

会員情報登録用にモデルを作成してバリデーションを設定しておきます。以下の設定は各配列の message を確認して頂ければ分かるかと思います。beforeSave() では入力されたパスワードを CakePHP の AuthComponent::password() を使ってハッシュ化して、データベースに直接平文のパスワードが入らないようになっています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class User extends AppModel {
 
    public $name = 'User';
    public $validate = Array(
        'email' => Array(
            'required' => Array(
                'rule' => Array('notEmpty'),
                'message' => 'メールアドレスを入力してください。'
            )
        ),
        'password' => Array(
            'required' => Array(
                'rule' => Array('notEmpty'),
                'message' => 'パスワードを入力してください。'
            )
        ),
        'role' => Array(
            'valid' => Array(
                'rule' => Array('inList', Array('admin', 'staff', 'author')),
                'message' => '権限を選択してください。',
                'allowEmpty' => false
            )
        )
    );
 
    public function beforeSave() {
        if (isset($this->data[$this->alias]['password'])) {
            $this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
        }
        return true;
    }
}

ビュー

ビューは複数あります。index.ctp、login.ctp、logout.ctp、add.ctp が必要となります。ちなみに index.ctp と logout.ctp は内容は特になくても構いません。アクセスさえ出来れば問題ありませんので、ここでは複雑になる login.ctp と add.ctp のサンプルを紹介します。

まず login.ctp が以下となります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="login form">
    <?php echo $this->Session->flash('auth'); ?>
    <?php echo $this->Form->create('User', Array('url' => '/admin/login')); ?>
    <table>
    	<tr>
    		<th>メールアドレス</th>
            <td><?php echo $this->Form->input('email', Array('label' => false)); ?></td>
    	</tr>
    	<tr>
    		<th>パスワード</th>
            <td><?php echo $this->Form->input('password', Array('label' => false)); ?></td>
    	</tr>
    </table>
    <?php echo $this->Form->end('ログイン'); ?>
</div>

次に add.ctp が以下となります。

1
2
3
4
5
6
7
8
9
10
11
<div class="admin form">
    <?php
        echo $this->Form->create('User', Array('url' => '/admin/add'));
        echo $this->Form->input('email');
        echo $this->Form->input('password');
        echo $this->Form->input('role', array(
            'options' => array('admin' => '管理者', 'staff' => 'スタッフ', 'customer' => 'お客様')
        ));
        echo $this->Form->end('アカウントを作成する');
    ?>
</div>

それぞれの役割はコードを読んで頂ければ分かるかと思います。

実際にテストする

実際にテストをしてみます。以下の手順で無事動作することを確認してみてください。

  1. /admin/add にアクセスしてテストユーザーを作成
  2. /admin/login にアクセスしてログインのテスト
  3. /admin/logout にアクセスしてログアウトのテスト

わざとログイン情報を間違えたり、ログインの再度実行で実際に発行されている SQL を確認するなどして色々確認してみましょう。

おわりに

非常に簡単な説明となりますが以上となります。CakePHP 1.x 時代に一度実装した覚えがあるのですが、不安だったためかブログ記事化していませんでした。今回 CakePHP 2.x 系でログイン機能を構築しましたので、忘れないようにメモをしておきました。久しぶりかつ CakePHP 2.x 系では初めての実装になるので、間違っている点があればご報告頂けると修正することができますので、よろしくお願い致します。

コメント

  1. aggreさんのコメント

    とても参考になりました。ありがとうございます。
    userテーブルの作成に使うSQLですが、今回の場合でしたら1行目は
    『CREATE TABLE IF NOT EXISTS `users` (』
    ですよね。

    • webleさんのコメント

      仰るとおり users となります。記事中のテーブル名は誤りとなりますので訂正させて頂きました。ご指摘頂きありがとうございました。