ログイン機能を実装する
これでユーザ認証機能を実現するための準備が整いました。ここからはアクション側の実装について説明します。
まずはログイン機能を実装します。Root.pmにloginアクションとして次のように記述しました。
sub login :Local { my ( $self, $c ) = @_; # POST以外の場合にはテンプレートを表示 if ($c->request->method ne 'POST') { return; } my $username = $c->request->params->{username}; my $password = $c->request->params->{password}; if ($username && $password) { # ログイン処理 if ($c->authenticate( { username => $username, password => $password })) { $c->response->redirect($c->uri_for('/')); } else { $c->stash(error_msg => 'ユーザ名またはパスワードが間違っています。'); } } else { $c->stash(error_msg => 'ユーザ名またはパスワードが指定されていません。'); } }
ログイン処理は、プラグインによりコンテキストオブジェクトに追加されたauthenticateメソッドを使用して行います。
このサンプルでは、ログインした場合にはルートにリダイレクトしています。また、ユーザ名、パスワードが指定されていない場合、または間違っている場合にはエラーメッセージを表示するようにしています。
次にログインテンプレートファイルを見ていきましょう。
[%- IF !c.user_exists -%] [% # (1)ユーザがログインしていない場合 %] <form method="post" action="[% c.uri_for('/login') %]"> <table> <tr> <td>ユーザ名:</td> <td><input type="text" name="username" size="40" /></td> </tr> <tr> <td>パスワード:</td> <td><input type="password" name="password" size="40" /></td> </tr> <tr> <td colspan="2"> <input type="submit" name="submit" value="ログイン" /> </td> </tr> </table> </form> [%- ELSE -%] [% # (2)ユーザがログインしている場合 %] <div> ログインしています<br /> </div> [%- END -%]
このテンプレートでは、ユーザがログインしている場合には、ログインフォームを表示せずメッセージを表示するようにしています。
ユーザがログインしているかどうかは、コンテキストオブジェクトに追加された「user_exists」メソッドによって判定することができます。
ログアウト機能を実装する
次にログアウト機能について見ていきます。明示的にログアウト機能を実装しない場合には、認証状態の有効期限は、セッションの有効期限に依存します。つまりセッションプラグインのexpiresパラメータで指定した値になります。
sub logout :Local { my ( $self, $c ) = @_; # (1)ログアウト $c->logout(); # (2)ログアウト後にはルートにリダイレクト $c->response->redirect($c->uri_for('/')); }
ログアウト処理を行うには、(1)のように、その名前のとおりの「logout」メソッドを呼び出します。またこのサンプルでは、ログアウト後には(2)ルートにリダイレクトしています。
セッションカウンターページをログイン必須にする
次に、認証されたユーザのみ閲覧可能なページが閲覧されようとした場合に、ログインしていなければログインフォームにリダイレクトさせるという処理を追加してみましょう。
それぞれのページに処理を組み込むことももちろん可能ですが、Catalystの組み込みアクションである「auto」を使用すれば複数のページに対してログインを必須とする処理を簡単に組み込むことができます。
ここでは、「session_counter」ページに対してログインを必須とする処理の例を見ていきましょう。
sub auto :Private { my ( $self, $c ) = @_; # (1)呼び出されたアクション名が「session_counter」の場合 if ($c->action->reverse eq 'session_counter') { # (2)未ログインならばログインフォームにリダイレクト if (!$c->user_exists) { $c->response->redirect($c->uri_for('/login')); return 0; } } # (3)対象アクション以外には処理を継続 return 1; }
呼び出されているアクションによってログインチェックを行う場合には、(1)のようにCatalyst::Actionのreverseメソッドによって判定することができます。このメソッドは、現在実行されているアクション名を返します。
もし対象とするアクションが呼び出されている場合には、(2)user_existsメソッドによってログイン状態かどうかを判定し、未ログインの場合にはログインフォームにリダイレクトし、それ以降のautoアクションを実行しないようにします。
対象となるアクション以外の場合、またはログイン済みの場合には(3)のように1を返すことで、本来のリクエスト処理を継続します。
実行例
それでは、ログイン画面を表示してみましょう。次のURLをブラウザで表示させます。
http://<ホスト名またはIPアドレス><:Port>/login
まず、ログイン画面は次のようになります。
指定したユーザ名またはパスワードが間違っている場合には、次の画面が表示されます。
すでにログインしている場合に、ログインURLにアクセスすると、次のように「ログインしています」と表示されます。