― Web Technology and Life ―

PerlのWAFのAmon2でTwitterのOuth認証を作るの巻

2012-12-10
TwitterやれFacebookやれでOuth認証してウェブサイトのユーザー登録を簡易化、兼、個人情報を持たなくてハッピーな展開がいろんなサイトでも見受けられる今日この頃ですが、PerlのWAFのAmon2では簡単にこの実装ができちゃうよってことで、その備忘録でございます。

【前置き】Amon2はWeb周りの実装が充実している

tokuhiromさんがオーサーのPerlのWAF(ウェブアプリケーションフレームワーク)のAmon2ですが、軽量・高速とコードが少ないということで、今度のWEB+DBでも記事が出るそうでとても楽しみな今日この頃なのですが、DancerとかMojoliciousとか軽量と言われるその他のWAFと比べてどうか知りませんが、軽量といってもプラグインで以下のようなウェブ周りのプラグインが充実しているので、結構、使いやすいように思えます。

  • Amon2::Plugin::Web::WebSocket
  • Amon2::Plugin::Web::MobileAgent
  • Amon2::Plugin::Web::FillInForm
  • Amon2::Plugin::Web::Auth

特に、MobileAgentは、ガラケー対応とかいまさらねーという感じですが、UAの振り分けとか、文字コードとかめんどかったりがあると思うのですが、そのあたりもさくっと対応できるので、「いまさらガラケー対応するのはコスト的に・・・」という話をするんじゃなくて「まぁ、デザインこらなければ、無料で・・・」という感じ話が制作会社ならできちゃうんじゃないかという感じのお得感満載です。

ウェブ周りじゃなくても、ログとかDB周りとかテンプレートエンジン周りも一定の推薦的な道筋があるので、わりと充実しているんじゃないでしょうか。強いて言えば、バリデーターくらいでしょうかねー、バリデーションはJSで実装するのか、JSで実装するけど判定自体はサーバーサイドで実装するのか、なんとも悩ましい感じなんですかねー、ぼくはウェブアプリってこのブログくらいしか作ってないのでまぁよくわからないのですが。。。苦笑

で、前置きはこれくらいにして、本日は、先のリストの最後に上げた「Amon2::Plugin::Web::Auth」、ディストリビューション的には、Amon2::Authを使ったTwitterのAuth認証を取り上げてみたいと思います。

Auth認証の実際とAmon2::Authの既存事例記事

Auth認証の実際

Auth認証は、FacebookやれTwitterやれで、対応しているAuthのバージョン(?)が違うので、実装ベースではなんだかゴミゴミしていてわかりづらいっすね。ぼくは、TwitterとFacebookの実装を以前勉がてらやろうと思ったんですが、よくわからんと思い、結局Amon2::Authを作って済ませてしまいましたw 本来は、自分でしっかり実装したほうが理解が深まると思うのですが、だいたい忘れるので、まぁ簡単にできるものがあればそれに越したことはないんじゃないでしょうか?ちなみに、ゆーすけべーさんの『Webサービスの作り方』に「イカ娘でTwitter Auth認証」という記事があって、それは自前でコジコジ実装しているので、参考になるんじゃないかと思います。

既存事例記事

こうやって実装するんだよっていう既存の記事があるのですが、それはTwitterはないんですね。

まぁ、でも、なんとなくこのあたりを読めば分かる人はわかると思いますね。

それで、実際のTwitter Auth認証をAmon2で

とりあえず、Amon2::Authを使うのですが、先に述べた通りPODを読んでもいまいちわからないので、いまいちAuthの仕組みが頭に入っていないぼくにとってはそのへんも加味して、この備忘録に至ったわけですね。

実装の概要編

とりあえず、Pluginの使い方はややこしいのですが、基本的に以下のところに設定を書くことになると思います。

  • ①ConfigにAmon2::AuthのTwitter用の設定を記述
  • ②WebのPluginにAmon2::Authの設定
  • ③psgiの設定にセッションを追加・変更(?)(Plack::SessionとPlack::Session::Store::*?)
  • ④HTMLにログインURLへのリンク(とログアウトのURLへのリンク)
  • ⑤(Dispatcherの設定に、ログアウトのURLを追加と、ログイン時が検証できるようなコードを追加)

実装のコード編

Amon2をLiteフレーバーで作っています、一枚アプリってやつですね。Amon2::Liteの使い方とかもろもろはこちらを御覧ください

先に上げている重要なポイントはコメントでかいてあります。

use strict;
use warnings;
use utf8;
use File::Spec;
use File::Basename;
use lib File::Spec->catdir(dirname(__FILE__), 'extlib', 'lib', 'perl5');
use lib File::Spec->catdir(dirname(__FILE__), 'lib');
use Plack::Builder;
use Amon2::Lite;
use Plack::Session::Store::File;
use Plack::Session::State::Cookie;


## ①Twitterの管理画面からとってきたconsumer_keyとconsumer_secretを設定
sub config {
    +{
        Auth => +{
            Twitter => +{
                consumer_key    => '******',
                consumer_secret => '******',
            },
        },
    }
}

## ⑤Dispatcherの設定
# Twitter認証がとれたような設定
get '/' => sub {
    my $c = shift;

    ## ログインできていることを確認するために、なんとなくセッションから情報をとる
    return $c->render('index.tt',{
        user_id => $c->session->get('user_id') || 'undefine',
        name    => $c->session->get('name')    || 'undefine',
    });
};

# ログアウトのときはセッションをきるためにExpire
get '/logout' => sub {
    my ($c) = @_;
    $c->session->expire;
    $c->redirect('/');
};

# Amon2::Liteのデフォルトのセキュリティ対策の設定
__PACKAGE__->add_trigger(
    AFTER_DISPATCH => sub {
        my ( $c, $res ) = @_;
        $res->header( 'X-Content-Type-Options' => 'nosniff' );
        $res->header( 'X-Frame-Options' => 'DENY' );
    },
);

# load plugins
__PACKAGE__->load_plugins(
    'Web::CSRFDefender',# Amon2::Liteのデフォルトのセキュリティ対策の設定

    ## ②AuthのPlugin設定、ログイン後のURLをTOP以外にしたければ、$c->redirect('/')を変更
    'Web::Auth' => +{
        module      => 'Twitter',
        on_finished => sub {
            my ($c, $access_token, $access_token_secret, $user_id, $screen_name) = @_;

            $c->session->set('user_id'             => $user_id);
            $c->session->set('name'                => $screen_name);

            return $c->redirect('/');
        },
    },
);

builder {
    enable 'Plack::Middleware::Static',
        path => qr{^(?:/static/|/robot\.txt$|/favicon.ico$)},
        root => File::Spec->catdir(dirname(__FILE__));
    enable 'Plack::Middleware::ReverseProxy';

    ## ③セッション情報をためるために、Plack::Session::Store::*を設定しなくちゃだともいます(?)Cookieはいらないかな?
    enable 'Plack::Middleware::Session',
        store => Plack::Session::Store::File->new(
            dir => './sessions'
        ),
        state => Plack::Session::State::Cookie->new(
            httponly => 1,
        );


    __PACKAGE__->to_app();
};

__DATA__

## ④ログイン用のURLはプラグインで、デフォルトで/auth/twitter/authenticateに設定されている、Pluginの設定で変更できる(後述)
@@ index.tt
<!doctype html>
<html>
<head>
    <met charst="utf-8">
    <title>Auth</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <h1>Twitter Auth Test</h1>

    <h2>Login</h2>
    <p>
        <a href="/auth/twitter/authenticate">login</a> <br />
        <a href="/logout">logout</a> <br />
    </p>

    <h2>Your Profile</h2>
    <p>
    user_id:[% user_id %] <br />
    name:[% name %] <br />
    </p>

</body>
</html>

Sessionの設定は、Plack::Sessionって実際よく知らないので、もうちょっとコードを確認したいところなのです。。。storeとstateの設定をしないとどうなるのか、ちょっと今棚上げ中ですね。。。

個人的なポイント編

個人的にフリーズしたのが、TwitterとかFacebookに認証で飛ばすURLとかTwitterとかFacebookが認証終えて戻ってくるときのコールバックのURLとかどこに書くのよ?っていうところですね。

Amon2上のコールバックURLとログインURLについて

アプリのURLは、普通はDispatcherに書くもんだと思い込んでいると一見よくわからないんですね。つまり、ログインURLとコールバックURLはDispatherに設定するのではなく、Pluginに設定します。

Amon2::Plugin::Web::Authのコードを読むとわかるんですが、Twitterに限らず、実際は、Pluginの設定は以下のようになっています。authenticate_pathとcallback_pathで変更ができますね。

__PACKAGE__->load_plugins(
    'Web::Auth' => +{
        module            => 'Twitter',
        on_finished       => sub {
            my ($c, $access_token, $access_token_secret, $user_id, $screen_name) = @_;

            $c->session->set('user_id'             => $user_id);
            $c->session->set('name'                => $screen_name);

            return $c->redirect('/');
        },
        on_error          => sub {}, # defaultは sub { die "Authentication error in $module: $err"; },
        user_info         => "",     # facebookなどのAuth2で必要なやつ、Twitterは必要なし
        authenticate_path => "",     # defaultは、"/auth/${moniker}/authenticate"($monikerは、Amon2::Auth::Site::Twitterとかに sub moniker {"twitter"}で書いてある)
        callback_path     => "",     # defaultは、"/auth/${moniker}/callback"
    },
);

Authの設定は、アプリに認証を送るためのコードと、予め設定したコールバックURLからほげほげしたりするのが、めんどそうなんですが、実際問題、そのあたりをうまく抽象化しているのがAmon2::Authの秀逸なところなんですが、まぁ、Authって仕組み自体ぶっちゃけ複雑だからしょうがないですよねーw

Twitterでのconsumer_keyとかconsumer_secretの取得とコールバックURLの設定

あと、そもそも、Twitterもですが、consumer_keyとかconsumer_secretとかをとるときに、Twitter上でコールバックURLを設定しなくてはいけないところも、はじめてやるときのポイントですね。(このアカウント取得も、なんか久しぶりにやると忘れますね・・・)

まとめ

いまさらですが、Amon2::Plugin::Web::AuthのPODにパッチ送ればわかりやすいことに気が付きましたよw

あと、Plack::Sessionについては後々コード読んでからちゃんと追記するつもりではありますが、、、忘れるかもw

ちなみに、この記事は、とりあえず、ゆーすけべーさんの本読んで、「誰でも思い浮かぶだろ」「誰でも作れるだろ」「そんなのユーザー集まらないだろ」「そんなのユーザー集まってもたかが知れているだろ」っていうようなアイデアでも一旦かたちとしてのウェブサイトにしてしまおうかなーと思って、脇をかためているさなかののアウトプットでございます。

UIは一番良くわからないので、なんじゃそのしょぼしょぼ機能アプリって感じでも、たまーに日曜大工して、のんびり来年の年始にコードを後悔するくらいにしたいと思いますねー。公開してdisられて後悔するみたいな感じですねw

Perl update_at : 2012-12-10T11:16:05
hirobanex.netの更新情報の取得
 RSSリーダーで購読する   
blog comments powered by Disqus