Perl Hackers Hub

第1回 PSGI/Plack―フレームワークとサーバをつなぐエンジン (3)

この記事を読むのに必要な時間:およそ 4 分

PSGIミドルウェアを利用する

PSGIミドルウェアはアプリケーションと同様にコードリファレンスとして実装されますが,いちいち.psgiファイルに記述するのはあまり効率が良くありませんし,再利用性もありません。そこでPlackにはミドルウェアをモジュールとして利用するためのベースクラスPlack::Middlewareや,それを利用して実装された各種ミドルウェアが同梱されています注2)⁠

ここでは,これらのミドルウェアを利用して先ほどのTatsumakiアプリケーションを拡張してみましょう。

注2)
そのほか,コアには含まれないミドルウェアも各種CPANモジュールとしてアップロードされています。

Auth::Basic

PSGIアプリケーションに簡単なHTTP認証機能を付けるミドルウェアがAuth::Basicです。容易に拡張できるコールバックインタフェースを持っているため,データベースやLDAPLightweight Directory Access Protocolなどとの連携もできます。

まずは,先ほどのhello.psgiを開き,ミドルウェアを利用するコードを追加します。リスト5のように,Plack::Middleware::Auth::Basicをロードし,wrapメソッドを使ってPSGIアプリケーションのコードリファレンス$app->psgi_appに認証機能を追加します(2))⁠authenticatorはユーザ名,パスワードを受け取り,それが正しいかどうかを返すコールバック関数になります。また,Helloハンドラ内でも,認証されたユーザを$self->request->userから取得して画面に表示(1)するようにしてみます。

リスト5 Auth::Basicの追加

use strict;
package Hello;
use parent 'Tatsumaki::Handler';

sub get {
    my $self = shift;
    $self->write("Hello ", $self->request->user); ……(1)
}

use Tatsumaki::Application;
my $app = Tatsumaki::Application->new([
    '/hello' => 'Hello',
]);

use Plack::Middleware::Auth::Basic;                 
$app = Plack::Middleware::Auth::Basic->wrap(        
    $app->psgi_app,                                 
    authenticator => sub {                          │(2)
        my($user, $pass) = @_;                      
        return $user eq 'admin' && $pass eq 'gihyo';
    },
);

ブラウザでhttp://localhost:5000/helloをもう一度開いてみましょう。図6のように認証ダイアログが表示されるはずです。ここではコードに記述したように,ユーザ名「admin」⁠パスワード「gihyo」だけが正しい入力ペアとなっています。それ以外の値を適当に入力しても,再度ダイアログが表示されるだけでしょう。正しいパスワードを入力すれば,⁠Hello admin」と認証によって取得したユーザ名が出力されます。

Auth::BasicミドルウェアはCPANモジュールのAuthen::Simpleのインタフェースにも対応しているため,LDAPや.htpasswdファイルなどによる認証と簡単に連携できます。詳しくはオンラインドキュメントを参照してください。

図6 Auth::Basicによる認証機能の追加

図6 Auth::Basicによる認証機能の追加

Plack::Builder

先ほどの例では,ミドルウェアを通常のPerlモジュールのようにuseし,wrapメソッドを呼ぶことでミドルウェアを追加しました。この方法では利用するミドルウェアを増やしていく場合などに記述が長くなりがちで,ミドルウェアの実行順序などが直感的でないという問題があります。そこで用意されているのがPlack::BuilderモジュールによるDSLDomain Specific Languageドメイン特化言語)です。

Auth::Basicを利用したミドルウェアの例は,Plack::Builderを利用するとリスト6のように記述できます。ラップされるアプリケーションをbuilder { }で囲み,その上にenableミドルウェア名,オプション...;のようにスタックしていくイメージです。ミドルウェア名の「Plack::Middleware::」部分は省略できますし,モジュールはBuilderによって自動的にロード(require)されますので,記述を大幅に簡潔化できます。

リスト6 Builderによるミドルウェアの記述

# $appまではリスト5と同様

use Plack::Builder;

builder {
    enable "Auth::Basic", authenticator => sub { ... };
     $app->psgi_app;
};

たとえば,ここでは詳細を省きますが,スタティックファイルを配信するミドルウェアStaticやアプリケーションの実行時間をX-Runtimeヘッダに挿入するRuntimeミドルウェアと組み合わせるとリスト7のように書くことができます。図4で見たようにアプリケーションが真ん中にあるとすれば,builderの中で下の行にありアプリケーションに近いほうが,真ん中に近い位置にあることになります。よって,この.psgiファイルを実行すると,Auth::Basic⇒Static⇒Runtime⇒Tatsumakiアプリケーション⇒Runtime⇒Static⇒Auth::Basicの順番で処理が実行されます。ミドルウェアごとにアプリケーションの前に実行されるもの(認証など)⁠後に実行されるもの(出力ヘッダの挿入など)に種類が分かれていますので,ドキュメントなどを参照して,どの順番が最適かを検討してください。

リスト7 ミドルウェアの追加

# $appまではリスト5と同様

use Plack::Builder;

builder {
    enable "Auth::Basic", authenticator => sub { ... };
    enable "Static", path => qr/^\/images/, root => "/images";
    enable "Runtime";
    $app->psgi_app;
};

そのほかのミドルウェア

紙幅の都合ですべては紹介できませんが,PlackコアやCPANには便利な各種ミドルウェアがアップロードされています。

Session

Sessionミドルウェアはフレームワークにセッション管理機能を追加します。多くのフレームワークが自前でセッション管理を実装している場合がほとんどのため,執筆時点ではあまりメリットがありませんが,フレームワークからこのPlack::Middleware::Sessionを利用するためのアダプタを記述すれば,各種フレームワークでセッションを共有する,といったことが容易にできるようになります。SessionミドルウェアはCookieによりID管理を行い,ストレージには各種ファイルやmemcachedといったキャッシュバックエンドが利用可能です。

Debug

PythonのDjangoプラグインであるdjango-debugtoolbarやRackのミドルウェアrack-bugにインスパイアされて作成したミドルウェアがDebugです。このミドルウェアを有効にすると,HTMLページの右側にパネル図7が表示され,リクエストヘッダやレスポンス,各種フレームワークのログなどをクリックして見ることができます。開発時にはとても有用なミドルウェアでしょう。

図7 Debugパネル

図7 Debugパネル

著者プロフィール

宮川達彦(みやがわたつひこ)

1977神奈川県生まれ。東京大学理学部卒業後,2000年に(株)オン・ザ・エッヂ(現(株)ライブドア)入社,執行役員Chief Technology Architectとして開発などに携わる。2005年よりシックスアパート(株)に入社,現在は米Six Apart, Ltd.に勤務。ニュースコンテンツの再配信サービス「Bulknews」やフィードアグリゲータ「Plagger」の作者であり,日本を代表するPerlハッカーの一人。カンファレンスでの発表だけでなくイベントも数多く運営するなど,精力的に活動している。個人ブログはhttp://blog.bulknews.net/mt/など。

コメント

コメントの記入