CakePHP2.xで、Authコンポーネントを使って簡単認証する方法。
2019/12/10
CakePHP2.x(2.3.6)でAuthコンポーネントを使い、認証させる方法をポストします。
以前紹介した、CakePHP2.x及びDebugKitのインストールとともに初期状態をさくっと作るための忘備録です。
セッションの設定
ログイン関連にはセッションを使用するので、セッション関係の設定を行います。
app/Config/core.php の190行目付近変更します。
いくつか前のポストにもあるように単位が「秒」ではなく「分」って事に注意して設定します。
「セッションの保存先を、データベースにするよ」という設定です。
1440(分)は一日って意味です。
編集前
1 2 3 |
Configure::write('Session', array( 'defaults' => 'php' )); |
編集後
1 2 3 4 5 |
Configure::write('Session', array( 'defaults' => 'database', 'cookie' => 'SID', 'timeout' => 1440, // ←単位は分(60秒*24時間=1440分) )); |
テーブル作成
次に、セッションをデータベースに保存するって設定を行ったので、各種テーブルを作成します。
1.セッション保存用テーブル
1 2 3 4 5 6 |
CREATE TABLE IF NOT EXISTS `albeitshift_cake_sessions` ( `id` varchar(255) NOT NULL DEFAULT '', `data` text NOT NULL, `expires` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
2.ユーザ用テーブル
次にユーザ用テーブル。
Authコンポーネントでは、『id』『username』『password』が最低限必要なカラムとなるので、それらを含んだテーブルを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CREATE TABLE `albeitshift_users` ( `id` INT UNSIGNED AUTO_INCREMENT, -- ★必須 `created` DATETIME DEFAULT NULL, -- `modified` DATETIME DEFAULT NULL, -- `username` VARCHAR(255), -- ユーザ名★必須 `password` VARCHAR(255), -- パスワード★必須 `role` VARCHAR(255), -- ロール(役職) `email` VARCHAR(255), -- メールアドレス `sort_order` INT(11) default NULL, -- 並び順 `is_deleted` TINYINT NOT NULL default '0', -- 削除フラグ `publish` TINYINT NOT NULL default '1', -- 公開フラグ PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
コントローラー作成
では、コントローラーを作っていきます。
全部載せるのはちと面倒なので、重要なところだけ。
AppController
基底ファイルである AppController にコンポーネント設定を書き、全てのページに反映させます。
ハイライトされているところが、Authコンポーネント設定です。
beforeFilter() にある
1 |
$this->set('userinfo', $this->Auth->user()); |
にて、ログイン中のユーザ情報を取得、セットするようにしています。
app/Controller/AppController.php
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 54 55 56 |
class AppController extends Controller { // モデル public $uses = array('User'); // ヘルパー public $helpers = array('Html', 'Form', 'Js', 'Session'); // コンポーネント public $components = array( 'Paginator', 'DebugKit.Toolbar', 'Session', 'String', 'ImageUpload', // 以下、Authコンポーネント設定 'Auth' => array( // ログインページのパス 'loginAction' => array( 'controller' => 'users', 'action' => 'login', 'admin'=> true ), // ログイン後のページを指定 'loginRedirect' => array( 'controller' => 'users', 'action' => 'list' ), // ログアウト後の移動先 'logoutRedirect' => array( 'controller' => 'users', 'action' => 'login' ), // 未ログイン時のメッセージ 'authError' => 'あなたのお名前とパスワードを入力して下さい。', ) ); public function beforeFilter() { // ログイン中のユーザ情報をビューにセット $this->set('userinfo', $this->Auth->user()); // 全ユーザ取得 $user_data = $this->User->find( 'list', array( 'conditions' => null, 'fields' => array('User.username'), 'order' => null, 'recursive' => -1, ) ); $this->set('user_data', $user_data); } // 以下略 } |
(2014.02.19追記)
下で説明している「Adminルーティング」を使用し、管理者用ログイン画面のURLを
1 |
http://yourdomein.com/admin/users/login |
としたい場合は、Appコントローラーのコンポーネント設定の「ログインページのパス」へ
1 |
'admin' => true |
を設定するとうまくいくようです。
更に追記です。
(1)削除済みのユーザに関してはログインさせたくない等の条件
(2)デフォルトではusername と passwordの判定だが、メールアドレスにて判定したい
の条件が必要になった場合は、下記の設定を追加すると幸せになれます。
1 2 3 4 5 6 7 |
// 条件追加 'authenticate' => array( 'Form' => array( 'scope' => array('User.is_deleted' => 0), // (1)is_deletedが立っていないユーザを対象とする 'fields' => array('User.username' => 'User.email'), // (2)認証をusernameからemailカラムに変更 ) ), |
(追記ここまで)
UsersController
とりあえず、beforeFilter()、admin_login()、admin_logout()だけ。
"admin_"はプレフィックスを付けて管理画面とする、Adminルーティングてやつです。
詳しくは以前のポスト(CakePHP2.x で Admin Routing する方法。)を参照してください。
見ればわかると思いますが、特に目新しいことはしていません。
CakePHPの仕様で、AppControllerで beforeFilter() を指定している場合は、各コントローラーでも beforeFilter() が必要になるので、そのようにしています。
ログイン、ログアウトは非常に簡潔なルーチンで作成可能です。お手軽ですね。
略していますが、これ以外のアクションとしては(ごく普通に)ユーザの一覧、追加、修正、削除、インデックスページなどがあると思うので、それぞれ作成してください。
app/Controller/UsersController.php
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 54 55 56 57 58 59 60 61 62 63 |
class UsersController extends AppController { // モデル var $uses = array('User'); /** * */ public function beforeFilter() { // 親クラスのbeforeFilterの読み込み parent::beforeFilter(); // 全ユーザ情報を取得 $user_data = $this->User->find( 'list', array( 'conditions' => null, 'fields' => array('User.username'), 'order' => null, 'recursive' => -1, ) ); // 認証不要のページの指定 if ( count($user_data) == 0 ) { $this->Auth->allow('admin_login', 'admin_logout', 'admin_add'); } else { // ユーザが1人以上なら、ユーザ追加アクションも権限を必要とさせる $this->Auth->allow('admin_login', 'admin_logout'); } } /** * ログイン * */ public function admin_login() { // titleタグ $this->set('title_for_layout', ログイン'); if ( $this->request->is('post') ) { if ( $this->Auth->login() ) { $this->redirect($this->Auth->redirect('/admin/users/index')); } else { $this->Session->setFlash(__('ユーザ名、メールアドレス、パスワードが不正です。')); } } } /** * ログアウト * */ public function admin_logout() { $this->redirect($this->Auth->logout()); } // 以下略 } |
ビューの作成
と、あとは必要なビューとモデルを適当(適切)に作っていけば出来上がります。
新規ユーザ登録フォーム
このページは、ユーザが居ない初期状態の場合は認証なしで表示するよう、UsersController の beforeFilter() で設定しています。
app/View/Users/admin_add.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
echo $this->Form->create('User'); echo '<p>管理者名 : '; echo $this->Form->input('username', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; echo '<p>メールアドレス : '; echo $this->Form->input('email', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; echo '<p>パスワード : '; echo $this->Form->input('password', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; echo '<p>ロール : '; echo $this->Form->select('role', $mt_role, array('empty'=>false, 'value'=>'employee')); echo '</p>'; // ボタン echo $this->Form->end(__('登録実行')); |
ログインフォーム
app/View/Users/admin_login.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
echo $this->Form->create('User'); echo '<p>管理者名 : '; echo $this->Form->input('username', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; echo '<p>メールアドレス : '; echo $this->Form->input('email', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; echo '<p>パスワード : '; echo $this->Form->input('password', array('size'=>30, 'label'=>false, 'error'=>false, 'div'=>false)); echo '</p>'; // ボタン echo $this->Form->end(__('ログイン')); |
ログアウト後ページ
app/View/Users/admin_logout.ctp
1 2 3 4 5 6 |
echo '<h2>ログアウトしました</h2>'; echo '<ul>'; echo '<li>' . $this->Html->link('ログインページへ','admin_login') . '</li>'; echo '<li>' . $this->Html->link('新規作成','admin_add') . '</li>'; echo '</ul>'; |
indexページ
必要かどうかは分かりませんが、ログインしている人の情報を表示するページとします。
app/View/Users/admin_index.ctp
1 2 3 4 5 6 7 8 9 |
echo '<p>ようこそ!' . h($userinfo['username']) . 'さん</p>'; echo '<p>あなたの登録メールアドレスは' . h($userinfo['email']) . 'です。</p>'; echo '<h2>管理者 INDEXページ</h2>'."\n"; echo '<ul>'; echo '<li>' . $this->Html->link('ログアウト', 'logout', array(), 'ログアウトしてもいいですか?') . '</li>'; echo '<li>' . $this->Html->link('新規ユーザ作成', 'add', array()) . '</li>'; echo '</ul>'; |
モデルの作成
最後に、ユーザ登録時のバリデーションを行うモデルを作成します。
app/Model/User.php
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 54 |
<?php class User extends AppModel { var $name = 'User'; /** * ロール(役職)マスタ * */ var $mt_role = array( "admin" => '管理者', "employee" => '社員', "parttime" => 'アルバイト', ); // バリデーション public $validate = array( 'username' => array( 'required' => array( 'rule' => array('notEmpty'), 'message' => 'ユーザ名は必須です。' ) ), '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', 'employee', 'parttime', ) ), 'message' => 'ロール(役職)を選択して下さい。', 'allowEmpty' => false ) ) ); } |
以上で、最低限ユーザ認証させるページが出来上がりました。
以下は、順を追ったスクリーンショットです。
スクリーンショット
1. 初期ユーザを登録
/admin/users/add で、初期ユーザを登録します。
2. ログイン画面
admin/users/login
3. ログイン後画面(INDEX)
ログイン後は、インデックスページヘリダイレクトするようにしたので、インデックスページを表示します。
ログアウト後は、ログインページが表示されるはずです。
と、かなり早足でしたが、Authコンポーネントを用いた、認証システムの作成方法でした。
[tgAmazonItemLookup asin="B00AXTVWEG" related="1"]