AuthComponentを使いやすくするビヘイビア

CakePHP 1.2 の AuthComponent はとても便利なのですが、POSTされたパスワードの値を自動的に暗号化(hash)してしまうため、ユーザの create/update を行う際のバリデーションが困難になります。そこで AuthComponent を補助する AuthModel ビヘイビアを作ってみました。

auth_model.php – gist:188066

このビヘイビアを使うことで

  • 標準のバリデーション機能を使ってパスワード入力値を検証できるようになります
  • 「再入力」による確認を行うための 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'));
}

参考にしたサイト

Leave a Reply