ROUTE 3390

備忘録的な用途で書いていますが、どなたかの役に立つ事があれば嬉しいです。

MojoliciousでのSession管理

よくあるセッション管理って、アクセスしてきたユーザー(ブラウザ)にセッションIDを発行します。


サーバー側ではセッションIDをキーにして
色々な(ユーザーAAAで、ログイン済みといった)情報を保存しておきます。


ユーザーのブラウザにはセッションIDが、
サーバー側に色々な情報が保存されるわけです。

ユーザーは発行されるセッションIDしか分かりません。


しかし、Mojoliciousにある標準のセッション管理はまったく逆のようなもので
ユーザー側で(ブラウザに)色々と保存するようになっています。
これは簡単に改ざんが可能でセキュリティ的に良くないです。
Mojolicious::Sessionではsecretを設定する事でHMAC-MD5という暗号化を行い、改ざんによるセキュリティリスクは低くなっているようです。今度ちゃんと勉強しようと思います。


そこでMojoX::Sessionです。
これを使えばよくあるセッション管理が実現できます。
ユーザー側にはセッションIDだけ、
色々な情報はサーバー側に保存するようになるのです。


僕の場合はMongoDBというデータベースを使っているので、
MojoX::Session::Store::MongoDBを使いますが、他のDBでも
だいたい同じです。

use MojoX::Session::Store::MongoDB;
use MojoX::Session::Transport::Cookie;

こんな感じでuseします。

startupメソッドではこんな感じ

$self->plugin('session' => {
    store => MojoX::Session::Store::MongoDB->new(
	{
	    host => '127.0.0.1',
	    port => 27017,
	    database   => 'データベース名',
	    collection => 'テーブル名',
	}
    ),
    transport => MojoX::Session::Transport::Cookie->new,
    expires_delta => 3600,
    stash_key => 'mojox-session',
});

ちなみにMongoDBでcollection(テーブル)に認証が必要な場合は下記のようにする必要がありました。

さっきのに加えてこれもuseします。

use MongoDB::Connection;

そんででもってこう!

my $mongo_obj = MongoDB::Connection->new( host => 127.0.0.1:27017' );
$mongo_obj->authenticate( 'データベース名', 'ユーザー名', 'パスワード' );
$self->plugin('session' => {
    store => MojoX::Session::Store::MongoDB->new(
	{
	    mongodb => $mongo_obj->get_database( 'データベース名' ),
	    collection => 'テーブル名',
	}
    ),
    transport => MojoX::Session::Transport::Cookie->new,
    expires_delta => 3600,
    stash_key => 'mojox-session',
});

MojoX::Session::Store::MongoDBでは認証を受け取る仕組みが用意されていないので、
認証設定済みのMongoDB::Connectionメソッドを渡しているんですね。


expires_delta というのは有効期限です。
デフォルトは3600秒になっていますが、上の例ではあえて設定してあります。
単位は秒で、発行された時間よりこの時間を過ぎると新しいセッションを発行しま
す。

stash_key に指定したキーで、後からセッション情報にアクセス出来ます。

詳しい使い方はこちら

my $session = $self->stash('mojox-session'); #セッションオブジェクトが入ってる
$session->load; #保存されている情報を取得
$session->create unless $session->sid; #セッションが発行されていないようなら、新規発行
$session->data('データのkey'); #セッションに保存されている情報のうち、指定した値を取得
$session->extend_expires; #セッションの有効期限を再設定

MacOS X にMongoDBをインストールしてみた(CentOSもあるよ)

僕にとって記念すべき初めてのNoSQLがMongoDBとなりました。
今回はそのインストール手順をメモメモ

portでインストール

shell> sudo port install mongodb
## だいたい10分くらいかかった ##

必要なディレクトリとログファイルを作成して、さて起動

shell> sudo mkdir /var/lib/mongodb
shell> sudo touch /var/log/mongodb.log
shell> sudo mongod --dbpath /var/lib/mongodb --logpath /var/log/mongodb.log
all output going to: /var/log/mongodb.log

あ、あれ、、シェルに返ってこない。。(この表現が正しいかは分かりません)
ログを確認すると下記のようなメッセージが

Sat Nov 17 13:20:24 [websvr] admin web console waiting for connections on port 28017
Sat Nov 17 13:20:24 [initandlisten] waiting for connections on port 27017

admin web console ってなに?


調べたら、ブラウザで localhost:28017 にアクセスすると、MongoDBの管理画面が表示されとのこと。

たしかに、
へー こんなのあるんだ。


で、これはなんだろ
[initandlisten] waiting for connections on port 27017
ググったらここに書いてあった。
コネクション - Docs-Japanese - 10gen Confluence


どうやら固まったわけではなく、ユーザーの接続を待っているらしい。
んん?よくみたらmongodbの公式ページって日本語化されているんだ、、知らなかっ
た。 イイね♪


なんだそーいうことなら

shell> sudo mongod --dbpath /var/lib/mongodb --logpath /var/log/mongodb.log &
shell> mongo
MongoDB shell version: 2.0.2
connecting to: test
>

こんな感じでバックグラウンドで起動してmongoというコマンドを叩いたら
無事、起動してmongoのコマンドモードになりました。



#### CentOSではこうやりました。
yumリポジトリの追加

shell> vi /etc/yum.repos.d/10gen.repo
[10gen]
name=10gen Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0

そしてインストール!

shell> yum install --enablerepo=10gen mongo-10gen mongo-10gen-server.x86_64
mongo-10gen.x86_64

そんでもって起動!

shell> /etc/init.d/mongod start
Starting mongod: forked process: 9132
all output going to: /ver/log/mongo/mongod.log
child process started successfully, parent exiting
     [ OK ]

Mojoliciousを使ってみたよ

PerlフレームワークMojoliciousを使ってみたので、そのメモ。
マシンはMac OS X


ちなみに、Mojoliciousはドキュメントが日本語訳されていますよ
Home · yuki-kimoto/mojolicious-guides-japanese Wiki · GitHub


まずはCPANからインストール

$ sudo cpan
cpan[1]> install Mojolicious


次にドキュメントルートで、Webアプリケーションの雛形を作るコマンドを実行しました。

$ cd /var/www/
$ mojo generate app MojoTest
  [mkdir] /var/www/mojo_test/script
  [write] /var/www/mojo_test/script/mojo_test
  [chmod] mojo_test/script/mojo_test 744
  [mkdir] /var/www/mojo_test/lib
  [write] /var/www/mojo_test/lib/MojoTest.pm
  [mkdir] /var/www/mojo_test/lib/MojoTest
  [write] /var/www/mojo_test/lib/MojoTest/Example.pm
  [mkdir] /var/www/mojo_test/t
  [write] /var/www/mojo_test/t/basic.t
  [mkdir] /var/www/mojo_test/log
  [mkdir] /var/www/mojo_test/public
  [write] /var/www/mojo_test/public/index.html
  [mkdir] /var/www/mojo_test/templates/layouts
  [write] /var/www/mojo_test/templates/layouts/default.html.ep
  [mkdir] /var/www/mojo_test/templates/example
  [write] /var/www/mojo_test/templates/example/welcome.html.ep

自動で色々作られます。


ちなみにアプリケーション名はキャメルケースで指定する必要があります。
下記のようにアンダーバーとかを含めるとエラーになります。

$ mojo generate app mojo_test
Your application name has to be a well formed (camel case) Perl module name
like "MyApp".


さて、作成されたディレクトリやファイルについて簡単に説明

mojo_test/lib
コントローラーやモデルなど、これから作るWebアプリケーションの様々な処理をここに作っていきます。
mojo_test/t
テストモジュールはここに
mojo_test/log
ログの格納場所かなぁ?まだ分かってません。
mojo_test/public
静的コンテンツの置き場所。htmlとかjavascriptcss、画像なんかも?
mojo_test/template
動的コンテンツを表示するためのテンプレート。
mojo_test/script/mojo_test
index.cgiの原型みたいなの。ではこれを早速。。。

そのままでもいいんだろうけど、僕はひとつ上の階層にindex.cgiとしてコピー

$ cp mojo_test/script/mojo_test mojo_test/index.cgi

ファイルの場所を変えたので、ライブラリの指定を修正。

$ vi mojo_test/index.cgi
use FindeBin;
use lib "$FindBin::Bin/../lib";

ここんところを、、
こう!

use FindeBin;
use lib "$FindBin::Bin/lib";


MojoliciousにはHTTPサーバーが付いているので、morboコマンドでスグに確認が出来る。

$ morbo index.cgi
Server available at http://127.0.0.1:3000.

表示されたURLにブラウザでアクセスすればOK


では、index.cgiが実行されて、このような画面が表示されるまでの流れをざっ!と説明。
まずindex.cgiですが、MojoTest.pmを呼んでいるだけなので省略。

mojo_test/lib/MojoTest.pm

package MojoTest;
use Mojo::Base 'mojolicious';

# This method will run once at server start
sub startup {
  my $self = shift;

  # Documentation browser under "/perldoc"
  $self->plugin('PODRenderer');

  # Router
  my $r = $self->routes;

  # Normal route to controller
  $r->get('/')->to('example#welcome');
}

1;

呼ばれるのは、このstartupメソッドですね。

デフォルトだとPODRendererというプラグインを読み込んでいるようです。
これはブラウザでMojoliciousの使い方を見るためのものらしく、
アプリケーション作る際は消しちゃっていい箇所です。


このプラグインを読み込んでいると、さっきのURLに/perldocを追加すると
このように表示されます。

さて、処理の続きを、
$self->routes;というので、Mojolicious::Routesオブジェクトを取得します。
URLによって処理を枝分かれさせる、ルーティングを行います。

$r->get('/')->to('example#welcome');

これだと
http://127.0.0.1:3000/ へのGETメソッドリクエストであれば、
exampleコントローラーのwelcomeアクションを呼び出します。


このtoメソッドの引数は色々な指定方法があるようです。
また、get以外にpostだけでなく、putやdeleteもあるので、RestAPIを提供する場合にも利用出来ます。
更にgetやpostのようなリクエストメソッドに関係なく、指定したい場合はrouteというのを使えます。


詳しい用法は日本語訳のガイドを参考にすると良いですよ。
Mojolicious::Routes · yuki-kimoto/mojolicious-guides-japanese Wiki · GitHub


というわけで、次は mojo_test/lib/MojoTest/Example.pmです。
コントローラーと呼ばれるものです。

package MojoTest::Example;
use Mojo::Base 'Mojolicious::Controller';

# This action will render a template
sub welcome {
  my $self = shift;

  # Render template "example/welcome.html.ep" with message
  $self->render(
    message => 'Welcome to the Mojolicious real-time web framework!');
}

1;

先ほどのルーティングの指定により、welcomeアクションが呼ばれるわけですが、
ここでは単純にrenderというメソッドにより、レンダリングの指示と
その際にmessageというkeyと値を持つ、ハッシュを渡していて、これはこの後テンプレートで使えるようになります。


ここでポイントですが、コメントにもあるように、利用されるテンプレートは
mojo_test/templates/example/welcome.html.ep になります。
どうやらデフォルトではルーティングの時に指定された コントローラー名、アクション名がそのままテンプレートを決める事になります。


つっても、柔軟にテンプレート変更したいとかあると思います。
そんな時の詳しい用法は日本語訳のガイドを参考にすると良いですよ。
Mojolicious::Guides::Rendering · yuki-kimoto/mojolicious-guides-japanese Wiki · GitHub


さぁ最後です。テンプレート!
呼ばれたのは mojo_test/templates/example/welcome.html.ep

% layout 'default';
% title 'Welcome';
<h2><%= $message %></h2>
This page was generated from the template "templates/example/welcome.html.ep"
and the layout "templates/layouts/default.html.ep",
<a href="<%== url_for %>">click here</a> to reload the page or
<a href="/index.html">here</a> to move forward to a static page.

だいたいさっきブラウザで表示された内容ですね。
ポイントだけ説明します。

% layout 'default';
% title 'Welcome';

この1行目はレイアウトの指定で、mojo_test/templates/layout/default.html.ep を選んでいます。
2行目でそのレイアウトに対しtitleという変数を渡してる感じです。


テンプレートの中では <%= 変数名 %> とする事で、その値を埋め込む事が出来ます。

layout/default.html.epは下記のようになっています

<!DOCTYPE html>
<html>
  <head><title><%= title %></title></head>
  <body><%= content %></body>
</html>

なんか知らない変数がありますね。
実は <%= content %> というのは、このレイアウトを指定したテンプレートの事になります。

なので、さっきのテンプレートが、このレイアウトテンプレートの<%= content %>部分にガボッとハマる感じですね。


実際にページを作成する時はcssjavascriptを使うと思いますが、
それはmojo_test/public/の下に置いて、そこへのパスをlayoutテンプレートのヘッダで指定したりするわけです。


これで基本編おわり!

P-01Dの端末依存?

WebViewを使ったアプリを開発していて、開発環境のページにはBasic認証をかけている事はよくあるケースだと思います。


そんな時
setHttpAuthUsernamePassword(String host, String realm, String username, String password)
を使うと思うのですが、、


なぜかP-01Dという端末だけ、ここでエラーになる。
お客様のお探しのページが見つかりません−404 Not Found | NTTドコモ


エラーの内容はREAD_PHONE_STATEパーミッションが必要というもの。。
Manifest.permission | Android Developers


なんでここで必要なの?
いまのところP-01Dでのみ確認している。



へるぷみー

Mouse(Moose)で使うMouseX::Types::Path::Classが素敵

今日はMouseX::Types::Path::Classって素敵ですねってはなし。

例えば、ログを吐くディレクトリを今まではこうやって用意してた。

package Sasakure;
use Mouse;

has 'dir' => (
    is       => 'ro',
    isa      => 'Str',
);

__PACKAGE__->meta->make_immutable;
no Mouse;

sub BUILD {
    my $self = shift;
    $self->{dir} = '/var/log/service';
    return $self;
}
1;

MouseX::Types::Path::Classを使う。

package Sasakure;
use Mouse;
use MouseX::Types::Path::Class;

has 'dir' => (
    is       => 'ro',
    isa      => 'Path::Class::Dir',
    coerce   => 1,
);
__PACKAGE__->meta->make_immutable;
no Mouse;

sub BUILD {
    my $self = shift;
    $self->{dir} = '/var/log/service';
    return $self;
}
1;

こうなって何が嬉しいって、渡した文字列(ディレクトリパス)が
Path::Class::Dirのオブジェクトとなってセットされる。
もちろんPath::Class::Fileも指定出来るよ。
素敵ですねーー♪


Path::Class::Dirの使い方はこちら

HTTP Authorizationヘッダを環境変数にセットする

Apacheを利用している場合、デフォルト状態だと
Authorizationヘッダの中身を環境変数には入れてくれません。

プログラム上で認証処理を行いたい場合は、下記のようにRewriteRuleを使って
環境変数に格納してあげる必要があります。

.htaccess

RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

例は.htaccessですが、httpd.confでやってもいいと思います。


HTTP Authorizationヘッダというのは、HTTP通信において
認証を行うための値を格納する場所です。

BASIC認証とかだと、ユーザーが入力したユーザーIDやパスワードは
HTTPのAuthorizationヘッダに含まれて送信されるんです。


BASIC認証に限らずとも、認証を行うための値をやり取りする場合はこのヘッダを利用するのが一応マナーになっているらしいです。
(マナーというかHTTPプロトコルの設計?)


例えば特定のクライアントからしか叩かせたくないAPIを作る場合、
きっとWebエンジニア相手に
「認証キーはSasakureなんでそれをAuthorizationヘッダに入れてリクエストして下さい。」
とか言えばすぐ伝わるんだと思います。


リクエストCGIの例

#!/usr/bin/perl

use strict;
use warnings;

my $ua = LWP::UserAgent->new;
$ua->timeout(10);
my $req = HTTP::Request->new( GET => 'http://xx.xx.xx.xx/index.cgi');
$req->header( 'Authorization' => 'Sasakure' );
$ua->request($req);

exit;


index.cgiでは
$ENV{HTTP_AUTHORIZATION}によって「Sasakure」が取得出来るようになる。

MySQL Clusterの設定ファイルを作ってくれるツール

MySQL Clusterの設定ファイルを作ってくれるツールがあるんですね。
知りませんでした。

ほとんど動くものが出来たので便利でした。

http://www.severalnines.com/config/

英語ですが、ひとつひとつ翻訳して、分からないキーワードは調べて、、、

MySQL Clusterの勉強にもなりましたし、
やみくもにネットで探すより良いと思います。