Catalystで、いわゆるユーザ認証してログインしたユーザのみコンテンツをみせるようなものをつくるためには、現状の Catalyst::Plugin::Authentication::CDBI では不都合が多いので、 Catalyst::Plugin::Authenticate::CDBI (名前が紛らわしい。Authenticateです。もうすぐCPANにUPするらしい)を 使った方法でやってみました。あと、Catalyst::Plugin::Session::FastMmapも /trunk にあるものを使いました(Set-Cookie の expires 属性問題回避のためですChanges参照)。
Mixie というプロジェクト名で作成し、Mixie::M::CDBI::Users を作成するまでの 作業は以下のようになります。
% catalyst.pl Mixie % cd Mixie % cat mixie.sql BEGIN TRANSACTION; CREATE TABLE users ( uid int PRIMARY KEY NOT NULL, username varchar(100), password varchar(100) ); INSERT INTO "users" VALUES(1, 'Melody', 'Nelson'); COMMIT; % sqlite /some/path/mixie.db < mixie.sql % script/mixie_create.pl model CDBI CDBI dbi:SQLite:/some/path/mixie.db
次に lib/Mixie.pm の先頭部分を以下のように変更します。 プラグインの登録とその設定を追加します。
use Catalyst qw/-Debug Session::FastMmap Authenticate::CDBI/;
our $VERSION = '0.01';
Mixie->config(
name => 'Mixie',
session => {
expires => 60 * 60 * 24,
rewrite => 0,
storage => '/tmp/session',
},
authenticate => {
cdbi => {
class => 'Mixie::M::CDBI::Users',
username => 'username',
passowrd => 'password'
},
},
);
1)/login でフォームが表示される。2)/do_login にフォームデータを送信し /home へリダイレクトする。3)ログインしていない人は/home以下を見ることができない。4)/logout でログアウトする。 そんなものを作ってみます。
まずは /login 。まあ、フォームを出力するだけなので以下でOKです。 本来はテンプレートを使ったほうがよいでしょう。(例なのでズルしてます)
sub login : Global {
my ( $self, $c ) = @_;
$c->res->headers->content_type('text/html; charset=utf-8');
$c->res->output('
<form action="/do_login" method ="POST">
<input name="username" />
<input name="password" type="password" />
<input type="submit" />
</form>
');
}
次に /login 。実際にユーザ名、パスワードをチェックする部分ですが、 処理自体は C::P::Authenticate::CDBI で定義されている authenticate_cdbi() で行います。 認証に通った場合は session->{user} にユーザ名を入れて/home へリダイレクトします。認証に失敗すれば再度フォームを表示します。
sub do_login : Global {
my ( $self, $c ) = @_;
my $username = $c->req->param('username');
my $password = $c->req->param('password');
if ( $c->authenticate_cdbi( $username, $password ) ) {
$c->session->{user} = $username;
$c->res->redirect('/home');
} else {
$c->res->redirect('/login');
}
}
そして /logout。/do_loginで設定した session->{user} を消して、フォームへ戻ります。
sub logout : Global {
my ( $self, $c ) = @_;
undef $c->session->{user};
$c->res->redirect('/login');
}
最後に/home ですが、別のコントローラにしたほうが何かと便利なので 作成してしまいます。
% script/mixie_create.pl controller Home
そして、Mixie::C::Home の begin でログインしているのかどうかのチェックするようにします。(注意 lib/Mixie.pm の begin ではなく lib/Mixie/C/Home.pm の begin です。)
sub begin : Private {
my ( $self, $c ) = @_;
unless ( $c->session->{user} ) {
$c->req->action(undef);
$c->res->redirect('/login');
}
}
begin で /do_login で登録した session->{user} がなければ /loginへリダイレクトするようにします。 /home/show_friends /home/show_logs とか直接アクセスされても、認証に通ったユーザのみが 閲覧できるようになり、そうでないユーザはログインページに逆戻りします。
Home.pm の default には、とりあえず以下のようにしておきました。
sub default : Private {
my ( $self, $c ) = @_;
$c->res->headers->content_type('text/html; charset=utf-8');
$c->res->output('Hi, '.$c->session->{user}
.' you can <a href="/logout">logout</a>.');
}
では script/mixie_server.pl して動作を試してみてください。
C::P::Authenticate::CDBI は C::P::Authentication::CDBI と違って ユーザ名、パスワードのチェック部分に特化しています。 Authentication::CDBI は $c->login というメソッドを使うこともあって /login というURLが使えない(いや、抜け道はあるのだが)という不便さから開放されます。 まだまだ、Catalystは実例が少ないので「やり方」を見つけるのには 一苦労かかりますが 何かあったら trunk を覗きにいくというのが解決策かなぁとは思います。
Thanks for a nice post.
//chansen