WWW が登場して以来、開発者達は Web サイトに最新技術を適用して、新しい機能やウィジェットを追加し、ユーザーの注意を引こうと、またユーザーの生活を便利にしようとしてきました。最近では、平均的な Web ユーザーはインターネット上で、例えば買い物をしたり、情報を検索したり、フォーラムやコミュニティーに登録したり、オンライン・ゲームをしたり、他のユーザーとコミュニケーションをしたりしています。これらの活動の大部分で、ユーザーは通常、Web サイトに登録してログインする必要があります。これらの基本機能には特別な注意が必要です。つまり登録やログインは、ユーザーが簡単かつ迅速に行えてセキュアでなければなりません。開発者の観点から見ると、さまざまな新しい技術のおかげで、これらの機能の実装は日を追うごとに容易になっています。
この記事では、これらの技術をいくつか組み合わせ、非常に単純なログイン機能を Web サイトに実装する方法について学びます。
この実装は以下の 4 つのセクションに分かれています。
- 「SQL」セクションでは、ユーザー情報をデータベースに保存するためのテーブルの作成方法を定義します。
- 「HTML」セクションでは、CSS および JavaScript の参照とログイン・フォームを実装します。
- 「JavaScript」セクションでは、jQuery と JSON を使って Ajax 部分を処理します。
- 最後に、「Perl」セクションでは、ユーザー入力とデータベースとの間のやり取りを処理します。
「手順」セクションでは、すべてを 1 つにまとめるための手順を、順を追って説明します。この記事では前提として、読者が上に挙げた技術を既に理解しており、また Web 開発の経験があるものとします。これらの技術に関して十分な経験がある読者の方は、途中を省略して直接「手順」セクションに進むことができます。
この記事に含まれていない内容
もう 1 つの重要な注意点として、セキュリティー、つまりユーザー入力がデータやシステムへの脅威となり得るかどうかのチェックについては、この記事では説明しません。またユーザーのパスワードを保存するための暗号化手法についても説明しません。ただし、皆さんのシステムに潜在する脆弱性について調べ、セキュリティーや暗号化をコードに組み込むことを強く推奨します。
このログイン手法は非常に単純なので、users テーブルを構成するフィールドは、一意の id、一意の username、そして password という 3 つしかありません。
リスト 1. SQL コード
CREATE TABLE `mydb`.`users` ( `id` INT NOT NULL AUTO_INCREMENT , `username` VARCHAR(45) NOT NULL , `password` VARCHAR(45) NOT NULL , PRIMARY KEY (`id`) , UNIQUE INDEX `id_UNIQUE` (`id` ASC) , UNIQUE INDEX `username_UNIQUE` (`username` ASC) ); COMMIT; |
実際のデータの挿入と一意性の検証は、登録機能で行われるはずです。そのため、この記事ではそれらについては省略しています。ここでは前提として、ログインの実装に必要な適切なユーザー情報が既に users テーブルに追加されているものとします。
ただしテストのために、以下のコードを使う必要があるかもしれません。このコードは users テーブルに 2 つの単純なエントリーを挿入します。
INSERT INTO `mydb`.`users` (`id`, `username`, `password`) VALUES(1, 'username1', 'password1'); INSERT INTO `mydb`.`users` (`id`, `username`, `password`) VALUES(2, 'username2', 'password2'); COMMIT; |
MySQL を使用していない場合には、そのデータベースの SQL 構文は MySQL の場合と少し異なるかもしれません。
HTML ファイルには、ログイン・フォームと、CSS および JavaScript ファイルの参照が含まれています。
単純にするために、この記事ではログイン・フォームのデザインよりも、上記の技術の実装に焦点を絞ることにします。そのため、ここでは修正 MIT ライセンスの下で入手可能な、Blueprint CSS というフレームワークのソースを使用します。このフレームワークによってブラウザーの互換性の問題も気にする必要がなくなります。当然ですが、インターネット上には他にも、さまざまなデザインを実現できる無料の CSS 実装がたくさんあります。
Blueprint フレームワークについては「参考文献」を参照してください。
<link rel="stylesheet" type="text/css" media="screen, projection" href="http://www.blueprintcss.org/blueprint/screen.css" /> <link rel="stylesheet" type="text/css" media="screen, projection" href="http://www.blueprintcss.org/blueprint/plugins/buttons/screen.css" /> <link rel="stylesheet" type="text/css" media="print" href="http://www.blueprintcss.org/blueprint/print.css" /> <!--[if IE]><link rel="stylesheet" type="text/css" media="screen, projection" href="http://www.blueprintcss.org/blueprint/ie.css"><![endif]--> |
jQuery ライブラリーの他に、後ほど説明する JavaScript ファイル (login.js) への参照もあります。
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="login.js"></script> |
この記事を公開する時点で jQuery のバージョンは 1.4.4 でした。「参考文献」を参照して最新バージョンを選択してください。
ログイン・フォームは、username というテキスト・フィールド、password フィールド、そして submit ボタンで構成されています。
<form id="loginForm" name="loginForm" method="post" action="">
<fieldset>
<legend>Enter information</legend>
<p>
<label for="username">Username</label>
<br />
<input type="text" id="username" name="username" class="text" size="20" />
</p>
<p>
<label for="password">Password</label>
<br />
<input type="password" id="password" name="password" class="text" size="20" />
</p>
<p>
<button type="submit" class="button positive">
<img alt="ok" src=
"http://www.blueprintcss.org/blueprint/plugins/buttons/icons/tick.png" />
Login
</button>
</p>
</fieldset>
</form>
|
入力の生成元のテスト、つまり人間が入力したものか、あるいはコンピューターによって生成された入力であるかのテストのために、Captcha を使うこともできます。
Captcha については「参考文献」を参照してください。
図 1. ログイン・フォームのスクリーン・キャプチャー
ログイン・アクションの結果は div タグに表示されますが、ロード時には非表示になっており、後で JavaScript によって値が追加されます。
<div id="loginResult" style="display:none;"> </div> |
図 2. JavaScript によって返されたエラー・メッセージのスクリーン・キャプチャー
図 3. Perl スクリプトによって返されたエラー・メッセージのスクリーン・キャプチャー
図 4. Perl スクリプトによって返された成功メッセージのスクリーン・キャプチャー
リスト 2. login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Very simple login using Perl, jQuery, Ajax, JSON and MySQL</title>
<link rel="stylesheet" type="text/css" media="screen, projection"
href="http://www.blueprintcss.org/blueprint/screen.css" />
<link rel="stylesheet" type="text/css" media="screen, projection"
href="http://www.blueprintcss.org/blueprint/plugins/buttons/screen.css" />
<link rel="stylesheet" type="text/css" media="print"
href="http://www.blueprintcss.org/blueprint/print.css" />
<!--[if IE]><link rel="stylesheet" type="text/css" media="screen, projection"
href="http://www.blueprintcss.org/blueprint/ie.css"><![endif]-->
<script type="text/javascript"
src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="login.js"></script>
<style type="text/css">
#loginContent { width: 350px; margin: 100px auto; }
button[type] { margin: 0.5em 0; }
</style>
</head>
<body>
<div id="loginContent" class="container">
<div id="loginResult" style="display:none;">
</div>
<form id="loginForm" name="loginForm" method="post" action="">
<fieldset>
<legend>Enter information</legend>
<p>
<label for="username">Username</label>
<br />
<input type="text" id="username" name="username" class="text" size="20" />
</p>
<p>
<label for="password">Password</label>
<br />
<input type="password" id="password" name="password" class="text" size="20" />
</p>
<p>
<button type="submit" class="button positive">
<img alt="ok" src=
"http://www.blueprintcss.org/blueprint/plugins/buttons/icons/tick.png" />
Login
</button>
</p>
</fieldset>
</form>
</div>
</body>
</html>
|
CSS は一番の関心事項ではありませんが、この HTML コードにはフォームとボタンの見栄えを少し良くするためのインライン定義がさらに 2 つあります。
この HTML コードと追加の CSS 定義は W3C の妥当性検証サービスを使って妥当性検証されています。
W3C の妥当性検証サービスについては「参考文献」を参照してください。
ユーザーがログイン・フォームを送信すると、ユーザーが入力した内容は jQuery ライブラリーによって読み取られます。空のフィールドが送信されていないかどうかの非常に単純なテストにパスすると、Ajax を使って Perl スクリプト (login.pl) が呼び出されます。この Ajax 呼び出しで重要な点は、dataType パラメーターを json に設定している点です。
Perl スクリプトを呼び出した結果に応じて、error 関数または success 関数が呼び出されます。このコード・サンプルでは、どちらの関数も呼び出しの結果を loginResult という id の div タグに書き込みます。
呼び出しが失敗した場合には、jQuery の XMLHttpRequest.responseText、textStatus、errorThrown がサンプル・コードによって表示されます。
スクリプトの呼び出しに成功した場合には、呼び出しのレスポンスのテストが行われます。レスポンスの data 変数にエラー・メッセージが含まれていない場合には、Perl スクリプトによって users テーブルから取得したユーザーの id が成功メッセージと共に表示されます。成功の場合、このコード・サンプルではフォーム自体を非表示にし、div タグのみを表示しています。
リスト 3. login.js
$(document).ready(function(){
$("form#loginForm").submit(function() { // loginForm is submitted
var username = $('#username').attr('value'); // get username
var password = $('#password').attr('value'); // get password
if (username && password) { // values are not empty
$.ajax({
type: "GET",
url: "/cgi-bin/login.pl", // URL of the Perl script
contentType: "application/json; charset=utf-8",
dataType: "json",
// send username and password as parameters to the Perl script
data: "username=" + username + "&password=" + password,
// script call was *not* successful
error: function(XMLHttpRequest, textStatus, errorThrown) {
$('div#loginResult').text("responseText: " + XMLHttpRequest.responseText
+ ", textStatus: " + textStatus
+ ", errorThrown: " + errorThrown);
$('div#loginResult').addClass("error");
}, // error
// script call was successful
// data contains the JSON values returned by the Perl script
success: function(data){
if (data.error) { // script returned error
$('div#loginResult').text("data.error: " + data.error);
$('div#loginResult').addClass("error");
} // if
else { // login was successful
$('form#loginForm').hide();
$('div#loginResult').text("data.success: " + data.success
+ ", data.userid: " + data.userid);
$('div#loginResult').addClass("success");
} //else
} // success
}); // ajax
} // if
else {
$('div#loginResult').text("enter username and password");
$('div#loginResult').addClass("error");
} // else
$('div#loginResult').fadeIn();
return false;
});
});
|
非常に単純な実装の場合、Perl には CGI、DBI、DBD::mysql という 3 つのモジュールしか必要ありません。CGI モジュールにより、Perl スクリプトは Ajax によって送信される username と password の値を取得します。次に Perl スクリプトはデータベースに接続し、指定された値のユーザー id を選択するためのクエリーを実行します。このクエリーの結果を基に、エラー・メッセージまたは成功メッセージのいずれかとユーザー ID を含む JSON レスポンスが作成されます。Perl スクリプトはコンテンツ・タイプを application/json に設定し、その JSON ストリングを使って Ajax に応答します。そしてその JSON ストリングが jQuery によって data 変数に取り込まれます。
リスト 4. login.pl
#!/usr/bin/perl -T
use CGI;
use DBI;
use strict;
use warnings;
# read the CGI params
my $cgi = CGI->new;
my $username = $cgi->param("username");
my $password = $cgi->param("password");
# connect to the database
my $dbh = DBI->connect("DBI:mysql:database=mydb;host=localhost;port=2009",
"mydbusername", "mydbpassword")
or die $DBI::errstr;
# check the username and password in the database
my $statement = qq{SELECT id FROM users WHERE username=? and password=?};
my $sth = $dbh->prepare($statement)
or die $dbh->errstr;
$sth->execute($username, $password)
or die $sth->errstr;
my ($userID) = $sth->fetchrow_array;
# create a JSON string according to the database result
my $json = ($userID) ?
qq{{"success" : "login is successful", "userid" : "$userID"}} :
qq{{"error" : "username or password is wrong"}};
# return JSON string
print $cgi->header(-type => "application/json", -charset => "utf-8");
print $json;
|
有効な JSON レスポンスを作成するために、JSON バリデーターを使用する必要があるかもしれません。
JSON バリデーターについては「参考文献」を参照してください。
生成された JSON ストリングを表示する
以下のようにしてブラウザーで JSON ストリングをチェックすることができます。
$cgi->header(-type => "application/json", -charset => "utf-8");をprint $cgi->header;に変更します。- ブラウザーに http://your-domain-name_or_localhost/cgi-bin/login.pl?username=username1&password=password1 と入力します。
図 5. JSON ストリングのスクリーン・キャプチャー
- SQL コードを使って users テーブルを作成し (
mydbを適切な値に変更します)、そのテーブルに何らかのテスト・データを追加します。 - login.html と login.js をコピーし、Web サーバーの htdocs フォルダーに貼り付けます。Web サーバーの設定によってはフォルダー名が異なるかもしれません。
- login.pl をコピーし、Web サーバーの cgi-bin フォルダーに貼り付けます。Web サーバーの設定によってはフォルダー名が異なるかもしれません。
- Perl スクリプトの最初の行を皆さんがお使いのバージョンに合わせて変更します (ほとんどの場合、Unix では
#!/usr/bin/perlであり、Windows では#!\Perl\bin\perl.exeです)。また、mydb、localhost、2009、mydbusername、mydbpasswordも適切な値に変更します。 - ブラウザーに http://your-domain-name_or_localhost/login.html と入力します。
- ユーザー名とパスワードとして正しい値と誤った値を入力し、さまざまな結果を確認します。
重要事項
HTML ファイル、JavaScript ファイル、Perl ファイルが同じドメインにホストされていることを確認してください。同じドメインにホストされていないと、Ajax によって Perl スクリプトを呼び出す場合、そのスクリプトは同じドメイン上に呼び出しスクリプトとしてホストされていないため、同一生成元ポリシーに違反してしまい、エラーが発生します (data 変数が null になります)。また、同じ理由から、HTML ファイルを Web サーバーによって提供する必要があります。
同一生成元ポリシーについては「参考文献」を参照してください。
この記事の目的は、ログイン・サービス実装の出発点として使用可能な、最新の手法による非常に単純なコードを紹介することです。この記事のコードを基に、セキュリティーを含め、手の込んだ多くの機能を作成することができます。さらには、いったん考え方を理解できると、他のデータベースやプログラミング言語を使ってみたくなるかもしれません。
- Blueprint は修正 MIT ライセンスで提供される CSS フレームワークであり、ブラウザーの互換性の問題が解消されています。
- jQuery はクロスブラウザーの JavaScript ライブラリーです。多くの機能を備えており、例えば Ajax によるやり取りを単純化し、Web 開発を短時間で完成させることができます。
- jQuery の Ajax API についてのドキュメントには、非同期の HTTP (Ajax) リクエストを jQuery を使って実行する方法が説明されています。
- 最新バージョンの jQuery を入手してください。
- JSON はブラウザーとサーバーとの間で情報を交換するための、(XML よりも) 軽量のデータ・フォーマットです。
- JSONLint は JSON バリデーターです。
- Captcha は Web サイトから入力される情報の生成元をテストするための手段です。
- 同一生成元ポリシーは、異なるドメインのメソッドへのアクセスを防止するためのセキュリティー概念です。
- developerWorks の記事、「JSONP によるクロスドメインの通信: 第 1 回 JSONP と jQuery を組み合わせ、強力なマッシュアップを迅速に作成する」を読むと、同一生成元ポリシーによる制約を理解することができます。
- 標準に準拠したコードを実装できるように、W3C はマークアップ妥当性検証サービスと CSS 妥当性検証サービスを提供しています。
