Catalyst で Authentication

| 1 | 3

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 を覗きにいくというのが解決策かなぁとは思います。

3

taskpad や checkpad など、いろいろ便利だと思います。やりたいこ... 続きを読む

Catalyst 5.65 で、下記のプラグインを使って実装してます。 Catalyst::Plugin::ConfigLoader 0.03 Catal... 続きを読む

すごい遅ればせながら、最近Catalystを使い始めました。 で、「qootas.org/blog - Catalyst で Authenticatio... 続きを読む

1

Thanks for a nice post.
//chansen