認証とACLの実装中です
2009-03-28 00:00 /
先日の記事で少し書いたように、ただいま或る案件で管理画面を開発しています。PHP のフレームワークである KohanaPHP を使っていて、サードパーティの追加モジュールも幾つか公開されています。認証と ACL では、公式パッケージのオプションとして開発チームから提供されている Auth と、これを改変した Simple_Auth の二つがよく使われているようでした。どちらのモジュールもシンプルなつくりになっていて、Simple_Auth は Auth とは異なり Kohana の ORM に依存しない設計で書かれており、独自のデータ構造とメソッドを使います。
さて、はじめは Auth を使っていて認証まではうまくいったのですが、クッキーの書き込みがうまくいかずにページを遷移するとロールを引き継いでくれず、ログイン画面に戻ってしまいます。二日ほどあれこれ試したのですが、諦めて木曜日は Simple_Auth を試してみることにしたのでした。
結果から言うと、Simple_Auth の方が更に不可解な動作をしていて、認証すらできませんでした。Simple_Auth::instance()->disable_user( $id ) を使うとユーザの有効無効は切り替えられるので、データベースにはアクセスしているようです。データベースでも値が変わっているのは確認できました。しかし、ログイン画面から認証するときに $user というオブジェクトが正しく作られておらず、そのために認証が失敗することが分かりました。認証は、
Simple_Auth::instance()->login( $post_data[ 'username' ], $post_data[ 'password' ], TRUE )
というやりかたで直接メソッドを呼び出してブール値を戻してもらいます。Auth を使うときは、
Auth::instance()->login( $_POST[ 'username' ], $_POST[ 'password' ] )
と書きます。ところが、Simple_Auth で上記のように書くと、$post_data が存在しないというエラーが出ます。確かに、ふつう POST で受けた値は $_POST[ 'username' ] のようにストレートに書くか、あるいは $this->input->post( ‘username’ ); のように書くことが多く、実は $post_data[ 'username' ] なんて書き方は KohanaPHP では定義されていない筈です。ともかくこれは埒が明かず、$this->input->post() だとフォームから送られた値がきちんと出るので、
Simple_Auth::instance()->login( $this->input->post( ‘username’ ), $this->input->post( ‘password’ ), TRUE )
という具合に書き直したわけです。
それでも、Simple_Auth クラスのメソッドである login() の処理をトレースすると、
public function login( $user, $password, $remember = FALSE ) {
if ( empty( $_POST[ 'password' ] ) ) return FALSE;
if ( ! is_object( $user ) ) $user = new Auth_Users_Model( array( ‘username’ => $user, ‘password’ => $password ) );
if ( ! $user->check_id() ) return FALSE;
if ( is_string( $password ) ) $password = $this->hash( $password );
if ( ( intval( $user->active ) === 1 ) AND ( $user->password == $password ) ) {
if ( $remember === TRUE ) {
$token_model = new Auth_Users_Tokens_Model();
$token_model->user_id = $user->id;
$token_model->expires = time() + $this->config[ 'lifetime' ];
$token_model->save();
cookie::set( $this->config[ 'cookie_key' ], $token_model->token, $this->config[ 'lifetime' ] );
}
$this->complete_login( $user );
return TRUE;
}
return FALSE;
}
この青く強調したところで $user というオブジェクトが生成されておらず、それ以降の check_id() が偽になってしまうため、認証に失敗するという結論に至りました。そして、モデルの Auth_Users_Model というクラスを確認すると、username と(ハッシュ化する前の入力値としての)パスワードから配列をつくって渡すという手順に問題はありません。
まぁ、認証はともかく role の引き回しだけ工夫すれば、自前で書く方が早いかもしれません。続きは来週にします。
