ログイン画面を作る

まさか、こんな開設したばかりのブログにコメントをいただけるとは思ってもみなかったので、俄然やる気が出てきた。

ということで、さっそく管理画面の開発にとりかかる。

CMSに管理画面は必須ではないけれど、今回作りたいCMSは、表側で公開する内容をすべて裏側(管理画面)で管理(登録、編集、削除)することを前提に考えているので、まずはやることが多い管理画面から作っていきたいと思う。

管理画面と言えば、一般の方に見られないように管理者の認証を用意する必要がある。
BASIC認証で済ますのはなんなので、ログイン画面を作ってみたいと思う。

参考にさせていただいたのは、下記のページ。

cakephp1.2から、Authコンポーネントが使えるようになったということで、これを使ってみたい。

管理画面を作るにあたり、管理画面用のパスを決めてCakePHPに設定すると便利だということがわかった。
このあたりのことは、CakePHP 管理者用アクション | Shin x blogが特に参考になった。

まず、app/config/core.phpにある

Configure::write('Routing.admin', 'admin');

を有効にする。(行頭のスラッシュ二つを削除)
この最後の'admin'の部分が管理用のパスになる。

例)
公開アドレス:http://www.example.com/
管理アドレス:http://www.example.com/admin/

次に、controllerでの対応。

管理側で使うアクションには、上記のパス名(admin)を先頭につけるようにする。

例)
公開側でのアクション:index
管理側でのアクション:admin_index

あわせて上記に対応したviewも必要。
特にviewでは、管理側と公開側のページデザインも変えたいので、管理側のページ全体レイアウト用に下記のviewファイルも用意したい。

app/views/layouts/admin.ctp

CSSファイルも管理側用に用意しておくといいかも。

app/webroot/css/admin.css

さて、ようやくログイン画面にとりかかる。
ここからは、【CakePHP】AuthComponentについてのまとめが特に参考になった。

Authコンポーネントを使いこなすには、ある程度プロパティを事前に登録しておくといいみたい。

Authコンポーネントを使う宣言とか、エラーメッセージやログイン後のリダイレクト先などは、app_controller.phpのbeforeFilter()に設定しておく。

app/app_controller.php

PHP:
  1. class AppController extends Controller {
  2.  
  3. var $components = array('Auth');
  4.  
  5. function beforeFilter() {
  6.   $this->Auth->loginAction = '/admin/users/login';
  7.   $this->Auth->loginError = 'ログインエラーです';
  8.   $this->Auth->authError = 'ログインしてください';
  9.   $this->Auth->loginRedirect = '/admin/sites';
  10. }
  11.  
  12. }

さらに、各controllerの中でも、管理側のアクションと公開側のアクションとがあるので、各controller内のbeforeFilterで、認証が必要ないアクション(公開側のアクション)を指定する。

PHP:
  1. function beforeFilter() {
  2.     parent::beforeFilter();
  3.     $this->Auth->allow('admin_init');
  4.   }

このあたりのことは、まだ正式版が出ていない1.2独自の仕様が多いので、フロンティアスピリッツあふれる先人の方々のブログ等による情報がなくては、全く手がつけられなかったと思う。感謝、感謝。

ところで、ログインまわりの画面遷移は、下記の通りを想定している。

  1. ログイン画面にアクセス
  2. まだ管理ユーザが1件も登録されていない場合は、初期管理ユーザ登録画面に移り、管理ユーザを登録
  3. ログイン画面でユーザ名とパスワードを入力してログイン
  4. 認証確認後、管理画面のメイン画面へリダイレクト

データベースのほうは、Authコンポーネントに沿ったかたちでテーブルを用意。

SQL:
  1. CREATE TABLE `users` (
  2.    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  3.    `username` VARCHAR(255),
  4.    `password` VARCHAR(255),
  5.    `name` VARCHAR(255),
  6.    `fullname` VARCHAR(255),
  7.    `created` DATETIME,
  8.    `modified` DATETIME,
  9.    PRIMARY KEY (`id`)
  10. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

上記のように、usersテーブルを作ってusernameとpasswordの項目を作るだけで、あとはAuthコンポーネントがパスワードの暗号化とかをやってくれるみたい。
(saltはapp/config/core.phpにあるSecurity.saltを使っているので、CakePHPインストール時にちゃんとSecurity.saltを指定しておかないとね)

で、さっそくusers_controller.phpから作ってみる。
上記2のとおり、導入直後のように管理ユーザが1件も登録されていない場合、このままではログイン画面を出しても意味がないので、初期管理ユーザを登録する画面を用意して、まずはそちらを表示させようかと思う。

PHP:
  1. function admin_login() {
  2.     $this->pageTitle = 'ログイン';
  3.     $this->layout = 'admin_login';
  4.     if ($this->User->findCount()> 0) {
  5.       $this->render('admin_login');
  6.     } else {
  7.       $this->render('admin_init');
  8.     }
  9.   }

上記に合わせて、admin_login.ctpとadmin_init.ctpをviewに用意する。

app/views/users/admin_login.ctp

PHP:
  1. <div class="users form">
  2. <h2>ログイン</h2>
  3. <?php
  4.   if ($session->check('Message.auth')):
  5.     $session->flash('auth');
  6.   endif;
  7.  
  8.   echo $form->create('User', array('action' => 'admin_login'));
  9.   echo $form->input('username', array('label' => 'ユーザ名'));
  10.   echo $form->input('password', array('label' => 'パスワード'));
  11.   echo $form->end('ログイン');
  12. ?>
  13. </div>

app/views/users/admin_init.ctp

PHP:
  1. <div class="users form">
  2. <h2>ユーザ登録</h2>
  3. <?php
  4.   echo $form->create('User', array('action' => 'admin_init'));
  5.   echo $form->input('username', array('type' => 'text', 'label' => 'ユーザ名'));
  6.   echo $form->input('Password.password', array('type' => 'password', 'label' => 'パスワード', 'after' => '<span class="item_required">必須</span>'));
  7.   echo $form->input('Password.password_confirm', array('type' => 'password', 'label' => 'パスワードの確認', 'after' => '<span class="item_required">必須</span>'));
  8.   echo $form->end('登録');
  9. ?>
  10. </div>

ユーザ登録時に、パスワードの入力ミスを防ぐためにパスワードを2回入力してもらうようにするのだが、パスワードの確認用の項目はuserのモデルには入っていないので、この際だから、パスワード用のmodelを作ってみる。

app/models/password.php

PHP:
  1. class Password extends AppModel {
  2.  
  3.   var $name = 'Password';
  4.   var $useTable = False;
  5.  
  6.   var $validate = array(
  7.     'password' => array(
  8.       'minLength' => array(
  9.         'rule' => array('minLength', 4),
  10.         'message'=>'パスワードは4文字以上必要です。'
  11.       ),
  12.       'required' => array(
  13.         'rule' => VALID_NOT_EMPTY,
  14.         'message' => 'パスワードを入力してください。'
  15.       )
  16.     ),
  17.     'password_confirm' => array(
  18.       'checkCompare' => array(
  19.         'rule'=> array('checkCompare'),
  20.         'message'=>'入力パスワードが一致しません。'
  21.       ),
  22.       'required' => array(
  23.         'rule' => VALID_NOT_EMPTY,
  24.         'message' => 'パスワードを入力してください。'
  25.       )
  26.     )
  27.   );
  28.  
  29.   function checkCompare($field) {
  30.     foreach( $field as $key => $value ){
  31.       if (preg_match('/^(.+)_confirm$/', $key, $regs)) {
  32.         return $this->data[$this->name][$regs[1]] == $this->data[$this->name][$key];
  33.       }
  34.     }
  35.   }
  36.  
  37. }

checkCompare関数については、下記のページで公開されているものを利用させていただいた。

上記のmodelでvalidationしたパスワードを、改めてuserのmodelに入れ、さらにその他の項目をvalidation(パスワードについては必須チェックのみ)して登録する。

app/models/user.php

PHP:
  1. class User extends AppModel {
  2.  
  3.   var $name = 'User';
  4.  
  5.   var $validate = array(
  6.     'username' => array(
  7.       'unique' => array(
  8.         'rule' => array('isUnique'),
  9.         'on' => 'create',
  10.         'message' => 'そのユーザIDは既に登録されています。'
  11.       ),
  12.       'alphaNumeric' => array(
  13.         'rule' => array('alphaNumeric'),
  14.         'message' => 'ユーザIDは半角英数字のみ有効です。'
  15.       ),
  16.       'required' => array(
  17.         'rule' => VALID_NOT_EMPTY,
  18.         'allowEmpty' => false,
  19.         'required' => true,
  20.         'message' => 'ユーザIDを入力してください。'
  21.       )
  22.     ),
  23.     'password' => array(
  24.       'required' => array(
  25.         'rule' => VALID_NOT_EMPTY,
  26.         'allowEmpty' => false,
  27.         'required' => false,
  28.         'message' => 'パスワードを入力してください。'
  29.       )
  30.     )
  31.   );
  32.  
  33. }

結果として、現在の時点のusers_controller.phpはこんな感じ。

app/controllers/users_controller.php

PHP:
  1. class UsersController extends AppController {
  2.  
  3.   var $name = 'Users';
  4.   var $uses = array('User', 'Password');
  5.   var $helpers = array('Html', 'Form');
  6.  
  7.   function beforeFilter() {
  8.     parent::beforeFilter();
  9.     $this->Auth->allow('admin_init');
  10.     $this->layout = 'admin';
  11.   }
  12.  
  13.   function admin_login() {
  14.     $this->pageTitle = 'ログイン';
  15.     $this->layout = 'admin_login';
  16.     if ($this->User->findCount()> 0) {
  17.       $this->render('admin_login');
  18.     } else {
  19.       $this->render('admin_init');
  20.     }
  21.   }
  22.  
  23.   function admin_init() {
  24.     $this->pageTitle = '初期ユーザの登録';
  25.     $this->layout = 'admin_login';
  26.     if ($this->User->findCount()> 0) {
  27.       $this->redirect(array('action' => 'admin_login'));
  28.     } else {
  29.       if (!empty($this->data)) {
  30.         $this->Password->create();
  31.         $this->Password->set($this->data);
  32.         if ($this->Password->validates()) {
  33.           $this->data['User']['password'] = $this->Auth->password( $this->data['Password']['password'] );
  34.           $this->data['User']['fullname'] = '初期登録ユーザ';
  35.           $this->User->create();
  36.           $this->User->set($this->data);
  37.           if ($this->User->validates()) {
  38.             $this->User->save();
  39.             $this->redirect(array('action' => 'admin_login'));
  40.           }
  41.         }
  42.       }
  43.     }
  44.   }
  45. }

ふうっ、こんなところかな。
こんなんでいいのか、ちょっと不安。

Authコンポーネントとか、肝心なところはブラックボックスだが、まずは動くことが目標。
いずれソースを追ってみたい。

それにしても、結構時間がかかってしまった。
ブログにも慣れていないので、これを書くだけでもかなり時間がかかる。
今回はちょっと気合いを入れすぎた。このペースではもたないので、これからは少しずつ書きとめていきたい。

Tags:

  1. バルカ’s avatar

    最近CakePHPを使い始めた者です。
    Authコンポーネントは便利そうなのですが、パスワード周りの処理に困っていたのでとても参考になりました。
    パスワードモデルを作ってしまうのは素晴らしいですね。暗号化前のパスワードを取得できるのと、確認用パスワードとのチェックができるのとで一石二鳥ですね。
    それに今制作しているシステムは、公開側はMemberテーブル、管理側はUserテーブルで認証を行う予定なので困ってました。しかしこれもパスワードモデルを共通で使用して解決できそうです。
    とりあえず公開側のユーザ登録はうまくいきました。ありがとうございました!

  2. admin’s avatar

    バルカさん、コメントありがとうございます。

    このブログが少しでもお役に立てたとしたら、とてもうれしいです。

    私もCakePHP初心者なので、なにかおかしな点がありましたら、ぜひご指摘お願いします。

  3. Yokokawa’s avatar

    参考にさせていただきました。
    ありがとうございます^^

  4. admin’s avatar

    ご参考いただき、ありがとうございます。