Perlでセッション管理

復習を兼ねて。

セッション管理

今さら説明する必要はないと思いますが、HTTPプロトコルはクライアントからWebサーバーへのリクエスト毎にコネクションの接続/切断が行われるため、画面遷移が発生するとリクエストが同一クライアントから送信されたものか判断できません。
そのため、ログインからログアウトまでユーザ情報を保持する必要があるシステムでは、セッション管理という仕組みが必要です。


セッション管理を実現するには、以下のような方法が考えられます。

  1. 情報をサーバ、クライアント(ブラウザ)間で渡し続ける
    • hiddenフィールドやURLパラメータ
  2. 情報をクライアント(ブラウザ)に保存
  3. 情報をサーバに保存


今回は、"2"と"3"を併用する形としました。
クライアント(ブラウザ)側にはCookieでセッションIDのみを保存し、その他の情報はサーバ側のMySQLに保存することとしました。


Perlでの実装については、"Apache::Session"と"CGI::Session"モジュールを使い比べてみました。
以下のコードは、

  1. ログイン画面(user_auth.html)からユーザ名とパスワードを送信
  2. user_auth.cgiCookieへのセッションID設定とMySQLへのデータ格納
  3. session.cgiでセッション情報の確認
  4. logout.cgiでセッション情報の破棄

を行っています。
バリデーション処理は実装していません。

Apache::Session

まずは、セッション情報用のテーブルを作成します。

mysql> create table sessions (id varchar(32) not null primary key, a_session text, date_ref timestamp default current_timestamp);

(user_auth.html)

<html>
<head>
<title>User Authentication</title>
</head>
<boby>
<font size="4" color="#FF0000">User Authentication Form(Apache::Session)</font>
<form action="./cgi-bin/user_auth.cgi" method="POST">
    User Name : <input type="text" name="user_name"><br>
    Password : <input type="password" name="user_pass"><br>
    <button type="submit" name="submit" value="submit">AUTH</button>
</form>
</body>
</html>

(user_auth.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use Apache::Session::MySQL;

my $q = CGI->new;
my $user_name = $q->param('user_name');
my $user_pass = $q->param('user_pass');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my %session;
eval {
    tie %session, 'Apache::Session::MySQL', undef, { Handle => $dbh, LockHandle => $dbh };
    };
if ($@) {
    return undef;
}

my $sid = $session{_session_id};
$session{user_name} = $user_name;
$session{user_pass} = $user_pass;
untie %session;

my $cookie = $q->cookie(
    -name => 'session_id',
    -value => $sid,
    );

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    -cookie => $cookie,
    );

print "ユーザ$user_nameでログインしました。\n";
print "セッションIDは、$sidです。\n";
print "<br>\n";
print "<a href='./session.cgi' target='_self'>セッション確認</a>";

__END__

(session.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use Apache::Session::MySQL;

my $q = CGI->new;
my $sid = $q->cookie('session_id');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my %session;
eval {
    tie %session, 'Apache::Session::MySQL', $sid, { Handle => $dbh, LockHandle => $dbh };
};
if ($@) {
    return undef;
}

my $user_name = $session{user_name};
my $user_pass = $session{user_pass};
untie %session;

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    );

print "ユーザ名 : $user_name", "<br>\n";
print "パスワード : $user_pass", "<br>\n";
print "セッションID : $sid", "<br>\n";
print "<a href='./logout.cgi'>ログアウト</a>";

__END__

(logout.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use Apache::Session::MySQL;

my $q = CGI->new;
my $sid = $q->cookie('session_id');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my %session;
eval {
    tie %session, 'Apache::Session::MySQL', $sid, { Handle => $dbh, LockHandle => $dbh };
};
if ($@) {
    return undef;
}

tied(%session)->delete;

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    );

print "ログアウトしました。", "<br>\n";

__END__


http://search.cpan.org/dist/Apache-Session/Session.pm
http://search.cpan.org/dist/Apache-Session/Session/MySQL.pm

CGI::Session

セッション情報用のテーブルは、上記"Apache::Session"のものを使用します。
(user_auth.html)

<html>
<head>
<title>User Authentication</title>
</head>
<boby>
<font size="4" color="#FF0000">User Authentication Form(CGI::Session)</font>
<form action="./cgi-bin/user_auth.cgi" method="POST">
    User Name : <input type="text" name="user_name"><br>
    Password : <input type="password" name="user_pass"><br>
    <button type="submit" name="submit" value="submit">AUTH</button>
</form>
</body>
</html>

(user_auth.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use CGI::Session;

my $q = CGI->new;
my $user_name = $q->param('user_name');
my $user_pass = $q->param('user_pass');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my $session;
eval {
    $session = new CGI::Session('driver:MySQL', undef, { Handle => $dbh });
};
if ($@) {
    return undef;
}

my $sid = $session->id();
$session->param(
    -name => 'user_name',
    -value => $user_name,
    );
$session->param(
    -name => 'user_pass',
    -value => $user_pass,
    );

$session->close();

my $cookie = $q->cookie(
    -name => 'session_id',
    -value => $sid,
    );

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    -cookie => $cookie,
    );

print "ユーザ$user_nameでログインしました。\n";
print "セッションIDは、$sidです。\n";
print "<br>\n";
print "<a href='./session.cgi' target='_self'>セッション確認</a>";

__END__

(session.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use CGI::Session;

my $q = CGI->new;
my $sid = $q->cookie('session_id');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my $session;
eval {
    $session = new CGI::Session('driver:MySQL', $sid, { Handle => $dbh });
};
if ($@) {
    return undef;
}

my $user_name = $session->param('user_name');
my $user_pass = $session->param('user_pass');

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    );

print "ユーザ名 : $user_name", "<br>\n";
print "パスワード : $user_pass", "<br>\n";
print "セッションID : $sid", "<br>\n";
print "<a href='./logout.cgi'>ログアウト</a>";

__END__

(logout.cgi)

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use DBI;
use CGI::Session;

my $q = CGI->new;
my $sid = $q->cookie('session_id');

my $dbh = DBI->connect(
    'dbi:mysql:Database_Name',
    'Username',
    'Password',
    ) or die "cannot connect database : $!";

my $session;
eval {
    $session = new CGI::Session('driver:MySQL', $sid, { Handle => $dbh });
};
if ($@) {
    return undef;
}

$session->delete();
$session->flush();

print $q->header(
    -type => 'text/html',
    -charset => 'UTF-8',
    );

print "ログアウトしました。", "<br>\n";

__END__


CGI::Session - persistent session data in CGI applications - metacpan.org