CakePHP 1.2 の AuthComponent はとても便利なのですが、POSTされたパスワードの値を自動的に暗号化(hash)してしまうため、ユーザの create/update を行う際のバリデーションが困難になります。そこで AuthComponent を補助する AuthModel ビヘイビアを作ってみました。
このビヘイビアを使うことで
- 標準のバリデーション機能を使ってパスワード入力値を検証できるようになります
- 「再入力」による確認を行うための sameValue バリデータが使えるようになります
- データ更新時に「パスワード欄が空ならパスワードを変更しない」という動作を簡単に実現できます
以下、password カラムを備えた users テーブル(すなわち User モデル)を例に使い方を説明していきます。
まず User モデルに AuthModel ビヘイビアを登録してください。いくつか使用可能なオプションがありますが最後に説明します。
class User extends AppModel { var $actsAs = array('AuthModel'); }
次にユーザ登録用のビューを作ります。AuthComponent による自動変換処理を回避するため、パスワード入力用のフィールドには本来のカラム名とは異なる名前を使用してください。AuthModel ビヘイビアはデフォルトで password_input という名前を使用するので、特にこだわりがなければこの名前を使うことをおすすめします。またパスワード再入力確認用のフィールドも用意しておきます。こちらは名前は何でも構いません。下の例では password_confirmation にしています。
<?php echo $form->create('User'); echo $form->input('username', array('label' => 'ユーザ名')); echo $form->input('password_input', array('type' => 'password', 'label' => 'パスワード', 'value' => "")); echo $form->input('password_confirmation', array('type' => 'password', 'label' => 'パスワード(再入力)', 'value' => "")); echo $form->end('作成'); ?>
更新用のビューもほぼ同じ構成です。パスワードを空にした場合は変更されない、という説明書きを加えておきます。
<?php echo $form->create('User'); echo $form->hidden('id'); echo $form->input('username', array('label' => 'ユーザ名')); echo $form->input('password_input', array('type' => 'password', 'label' => 'パスワード', 'value' => "")); echo $form->input('password_confirmation', array('type' => 'password', 'label' => 'パスワード(再入力)', 'value' => "")); echo $form->end('更新'); ?> ※パスワードを空欄にした場合は更新されません
そしてこの password_input フィールドに対するバリデーションを User モデルに設定していきます。以下の例では3つの設定を行っています。
- 入力は必須(requiredルール)
- 文字数は6文字以上(lengthルール)
- 「再入力」フィールドと値が一致(confirmルール)
最後のルールは AuthModel ビヘイビアが提供する sameValue バリデータを使います。このバリデータに対する唯一のオプションは再入力用フィールドの名前です。
class User extends AppModel { var $actsAs = array('AuthModel'); var $validate = array('password_input' => array('required' => array('rule' => '/.+/', 'required' => true, 'allowEmpty' => false, 'last' => true, 'on' => 'create', 'message' => 'パスワードを入力してください'), 'length' => array('rule' => array('minLength', 6), 'allowEmpty' => true, 'last' => true, 'message' => 'パスワードは6文字以上で入力してください'), 'confirm' => array('rule' => array('sameValue', 'password_confirmation'), 'allowEmpty' => true, 'message' => 'パスワードと再入力の値が一致しません'))); }
それぞれのルールにおける required, allowEmpty, on, last オプションの設定が少し複雑ですが、よく分からなければCookbookを参照してください。
最後に UsersController です。beforeFilter 中で setAuthComponent メソッドを呼び出し、AuthComponent を登録しておきます(実は AuthComponent の中でデフォルトのhashアルゴリズムを使用している限り、この操作は必要ありません。しかし将来的に互換性の問題が発生する可能性もあるので、Userモデルのcreate/updateを行うコントローラでは必ず実行しておいてください)。
ユーザの追加/更新を行うadd/editアクションの中では特別な操作は必要ありません。
class UsersController extends AppController { function beforeFilter() { parent::beforeFilter(); $this->User->setAuthComponent($this->Auth); } function add() { if (!empty($this->data)) { if ($this->User->save($this->data)) { $this->Session->setFlash('ユーザを作成しました。'); $this->redirect('index'); } else { $this->Session->setFlash('エラーを修正してください。'); } } } function edit($id = null) { if(empty($this->data)) { if (!$id || !($row = $this->User->findById($id))) { $this->redirect('index'); } $this->data = $row; } else { if($this->User->save($this->data)) { $this->Session->setFlash('ユーザ情報を更新しました。'); $this->redirect('index'); } else { $this->Session->setFlash('エラーを修正してください。'); } } } }
注意
このビヘイビアを使用すると直接パスワード用カラムに値を設定して保存することができなくなります(セキュリティ上の配慮)。この制約を回避するには save メソッドの validate オプションを無効にして実行してください。
//ユーザ名 = パスワード = admin のユーザを追加 function install() { $initialUser = array('User' => array('username' => 'admin', 'password' => $this->Auth->password('admin'))); $validate = false; if($this->User->find('count') == 0) { $this->User->save($initialUser, $validate); } $this->redirect('/'); }
応用
データ更新時の「パスワード入力欄が空ならパスワードを変更しない」動作が不要な場合、required ルールの on => create オプションを取り除いてください。さらに、滅多にないことだとは思いますが、空のパスワードを許可する場合は下記の allow_blank オプションを有効にしてください。
オプション
| キー | 型 | デフォルト値 | 説明 |
|---|---|---|---|
| column | string | password | パスワードを保存するカラムの名前 |
| input | string | password_input | パスワード入力用のフィールド名 |
| allow_blank | bool | false | 空のパスワード使用可否 |
| hash_function | callback | array(Security,hash) | パスワードのハッシュを求める際に使用するコールバック |
全てのオプションを設定した場合の例:
class User extends AppModel { var $actsAs = array('AuthModel' => array('column' => 'secret', 'input' => 'secret_input', 'allow_blank' => true, 'hash_function' => 'md5')); }