サイトのアプリケーションには、管理者による操作が必ず必要である。しかし、ポータルサイトや業務用Webアプリケーションでもない限り、アクセス制御を準備しなければならないほどでもない。それ故、CakePHP の Auth コンポーネントは非常に重宝である。
この認証機能だが、よく利用するにもかかわらず次のアプリケーションを作るときには忘れており、前のプログラムをひっくり返して来ては時間を潰す羽目になっている。
これは、そんな情けない自分用の備忘録です … orz。
認証に必要なものは、
テーブルは、CakePHPのログイン機能でデフォルト利用されるカラム名、username と password を含むスキーマを定義しておくこと。後は Bake を使って、モデル、コントロール、ビューの各プログラムをチャッチャと作る。
そうそう、「さくらのインターネット」では、appディレクトリ名はデフォルトの「app」でないと、config に登録されている database.phpを読みに行ってくれないようだ。他がどうかは?
#php cake/console/cake.php bake
ちょっと頭を捻るのが、初めてユーザー登録するときのパスワード。
パスワードの生成には「Auth::password()」を利用するのだが、コントローラーにイキナリ「Auth」コンポーネンツ指定するとプログラムの実行ができないので指定しない。そうすると、パスワード生成ができない。
そこで、Auth コンポーネントが読み込まれていないとき、import して password()メソッドを利用するようにする。
function _mkPassword($str) { if (isset($this->Auth)) { return $this->Auth->password($str); } App::import('Component', 'Auth'); return AuthComponent::password($str); }
add コントローラ
if (!empty($this->data)) { $this->User->create(); $this->data['User']['password'] = $this->_mkPassword($this->data['User']['passwd']); unset($this->data['User']['passwd']; if ($this->User->save($this->data)) { :
パスワードの入力は、ビュー(add.ctp)で次のように設定している。
$form->input('passwd', array('type'=>'password'));
ユーザーモデルの validate 変数に、重複チェック関数を実行するように指定し、重複チェック関数を用意する。
重複チェックは、入力された username と同じ内容のデータがあるか検索する。検索した結果、自分自身(idが同じ)でないなら false を戻すようにする。
var $validate = array( 'username' => array( 'rule' => array('chkUnique'), // isUnique を指定すれば下のメソッドは不要 'message' => 'The name has already been existed.') );
重複してないか確認するメソッド
function chkUnique($data, $item) { $user = $this->find('first', array( 'condition' => array('username' => $data['username']), 'recursive' => -1)); if (!empty($user)) { if (!isset($this->id) || $this->id != $user['User']['id']) { return false; } } return true;
エラー発生時、validate の message をビュー表示するが、今回なぜか日本語だと「<div>」タグは出力されるが、メッセージ文が表示されなかった(1.2.3.8166)。
そこで、ビュー側で「<?php echo $form->error(‘User.username’, ‘登録済みです。’) ?>」として、とりあえず回避した。なお、$form->input のパラメータに ‘error’=>false を追加してエラー表示を抑止した。
パスワードとそれ以外のユーザーデータの編集で、各個アクションを用意するのは面倒くさい。そこで edit() メソッドでパスワードを書替えたり、書替えせずスキップしたりする方法を考える。
パスワードの書替えは、edit ビューでpassword が入力されているかどうかで判定する。edit() メソッドでは、入力データがあればパスワードを新たに設定し、なければスキップする。
if (!empty($this->data)) { if (!empty($this->data['User']['passwd'])) { $this->data['User']['password'] = $this->_mkPassword($this->data['User']['passwd']); } unset($this->data['User']['password']; :
(090722)
追加訂正
1.マニュアル見直したら、バリデーションルールに「isUnique」があった。試したところ、説明のようなメソッドを追加する必要もなく利用できた。無駄骨だった…(T_T)
2.$this->data で User.password を使うと、アクションで受け取った時点で既にハッシュ値が設定される。そのため未入力のチェックができないので、未入力チェックするため別途、 User.passwd なるパスワード入力変数を設けて利用することにした。