レベル: 中級 Tyler Anderson (tyleranderson5@yahoo.com), Freelance writer
2006年 1月 10日 この2回のシリーズでは、J2EE™(Java™ 2 Platform, Enterprise Edition)の宣言的セキュリティー(declarative security)と、Geronimoに組み込みのDerbyデータベースの使い方を解説します。具体的な例として、登録ユーザーを認証し、Geronimoアプリケーション・サーバーを使うWebサイトにアクセスします。セキュリティーはSQL型のデプロイメント・プランを使って制御されます。どのユーザー、あるいはどのグループがWebサイトにアクセスを許可されているかは、このデプロイメント・プランによって規定します。この第2回の記事では、JSP™(JavaServer Pages™)を使って新しいユーザーを登録し、第1回で示したインフラストラクチャー設定を使ってログインできるようにする方法を中心に解説します。
はじめに
第1回で、架空の会社Web Apps Corpはクライアント向けWebサイトを構築し、ユーザーがさまざまなレベルで認証できるようにしました。データベース・テーブルを作成し、アプリケーションのセキュリティー・デプロイメント・プランを作成してインフラストラクチャーを開発しました。GeronimoコンソールからGeronimoに組み込みのDerbyデータベースにユーザー・テーブルとグループ・テーブルを作成しました。次に、SQLLoginModuleにより、セキュリティーを実装しました。SQLLoginModuleはGeronimoに組み込みのDerbyデータベースに接続し、ユーザー名、パスワード、グループ名をログイン・ユーザーが入力した情報と照合し、既存のユーザーにフォーラムへのアクセスを許可します。
この記事では、第1回で作成した簡単なログイン・システムを拡張し、JSPを使ったユーザー・レジストリー・システムを追加します。それによって、新しいユーザーはクライアントのWebサイトに登録し、フォーラムにアクセスできるようになります。初めにJSPの概要、JSPの実装方法、およびGeronimoとの関係について学びます。次に、ユーザー登録のフォームを表示するJavaサーブレットを作成します。ユーザーは、このフォームにユーザー名、パスワード、およびeメール・アドレスを入力します。この情報は同じサーブレットに送られます。サーブレットはデータベースに接続し、ユーザーのログインを可能にする新しいユーザー情報が入った新しいレコードを挿入します。
設定
今回の準備をするには、このシリーズ第1回の「作業に取りかかる」セクションを参照してください。また、変更されたディレクトリー構造については、「ダウンロード」セクションから入手できるzipソース・ファイルの中にあるREADME.txtファイルを参照してください。
第1回で示した前提条件とJ2SDK(Java 2 SDK, Standard Edition)のほかに、J2EE 1.4とJSP 2.0が必要です。JSP 2.0はJ2EE 1.4に付属しており、Sun MicrosystemsのWebサイトから無料でダウンロードできます。
これで準備ができました。ではJSPの説明から始めましょう。
JavaServer Pages
JSPはJava技術形式のスクリプト言語です。WebページにJava言語を埋め込んだり、サーブレットとして働くJavaクラスを作成できます。JSPを使うと、他のスクリプト言語と同じように、Webページに実行要求した内容に基づいて動的にコンテンツを生成できます。ただし、JSPとサーブレットはJava言語で書かれているため、プラットフォームやデバイスに依存しないJavaの移植性からくる強みを持っています。
Geronimoの能力を最大限活用するには、Geronimoのアプリケーションを構築するときにJSPとサーブレットを理解することが重要です。これから、JSPで初めてのスクリプトを作成して、簡単な.jspファイルの作成方法を学びます。次に、サーブレットの作成方法を学びます。サーブレットはJSPで作成するスクリプトに似ていますが、プリコンパイルされるため、安全性は高まります。
JSPでスクリプトを作成する
JSPの最初のスクリプトでは日付を表示します。スクリプト全体をJava言語で書きます。jspscript.jspファイルを作成し、リスト1に示すように定義します。
リスト1.JSPでスクリプトを作成する
<%
System.out.println("The script has started");
java.util.Date d = new java.util.Date();
out.println("<html><body>");
out.println("This is my first script written in JSP!<br>");
out.println("The historic time of this event is: ");
out.println(String.valueOf(d) + "<br>");
%>
Text displayed outside of the JSP script.<br>
<%
out.println("You can mix and match how you display text.");
out.println("</body></html>");
%> |
次に、デプロイメント用の簡単なweb.xmlファイルを作成し、WEB-INFサブディレクトリーに保存します。リスト2に示すように定義します。
リスト2.単純な web.xml ファイル
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
</web-app>
|
Geronimoに.warファイルをデプロイするときは、どんなに簡単なものでもweb.xmlファイルが必要です。すべてのWebモジュール(.warファイル)にはデプロイメント記述子(web.xmlファイル)が必要であるためです。次のように入力して、.warファイルを作成します。
jar -cvf jsp.war jsp.war WEB-INF/web.xml
次のように入力して、Geronimoに.warファイルをデプロイします。
java -jar <geronimo-install-dir>/bin --user system --password manager deploy jsp.war
次に、ブラウザでhttp://localhost:8080/jsp/jspscript.jspを開きます。図1は、ブラウザ出力の例を示しています。
図1. スクリプトの出力を表示する
ここで、リスト1に戻ります。Geronimoを実行したコンソールに「The script has started」と表示されたことに注意してください。ブラウザに表示するテキストは、out.println()ステートメントを使うか、<% ... %>タグの外側にテキストを置いて指定します。他のJavaアプリケーションと同じように、日付も取得されています。
これはJSPが持つ能力の一例です。JSPを使うと、Geronimoの能力を最大限活用できます。後ほど、.jspスクリプトを使い、ユーザーがログアウトできるようにします。
ここで、「ダウンロード」セクションで入手できるサンプル.zipファイルのlogout.jspスクリプトを見てみましょう。JSPを使い、フォーラムからユーザーをログアウトさせる機能がクライアントのアプリケーションに追加されています(ブラウザを閉じてログアウトするのではありません)。
次に、Javaサーブレットを作成します。
Javaサーブレットを作成する
このJavaサーブレットでは、ユーザー情報の取得と表示が簡単にできます。RegisterServlet.javaファイルを作成し、./src/servlets/RegisterServlet.javaディレクトリーに保存します。リスト3に示すように定義します。
リスト3.Javaサーブレット
package servlets;
import java.io.*;
import java.util.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RegisterServlet extends HttpServlet {
public static final String form =
"<form method='post'>\n" +
"Name:<br>\n" +
"<input name='username' size='25'><br>\n" +
"Email:<br>\n" +
"<input name='email' size='25'><br>\n" +
"Password:<br>\n" +
"<input type='password' name='password' size='25'><br>\n" +
"<input type='submit' value='Submit'>\n";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setBufferSize(8192);
PrintWriter out = response.getWriter();
out.println("<html>" +
"<head><title>Register</title></head>" +
"<body>" +
"<h1>Register</h1>\n" +
form +
"</form></body></html>");
out.close();
}
public String getServletInfo() {
return "Register!";
}
}
|
太字の1行目でサーブレットのパッケージservletsを設定しています。このパッケージはサーブレットがあるディレクトリー名に対応する必要があります。したがって、./src/servlets/に保存しました。このサーブレットがサーブレットであるのは、HttpServletクラスを拡張し、GET要求に応答するdoGet()メソッドがあるためです。応答のコンテンツ・タイプはdoGet()メソッドの先頭行にtext/htmlと設定されています。応答のバッファー・サイズも設定され、出力ストリームは応答からout変数に取得されます。最後にフォームが表示されます。実際のフォームはクラス宣言の後のString form変数に保存されます。メソッドはPOSTです。デフォルト・アクションでは、フォームのデータをこのサーブレットに戻します。フォームにはユーザー名、パスワード、およびeメールアドレスのユーザー情報を入力できる3つのテキストボックスがあります。
したがって、新しいユーザーは情報を入力し、サーバーに送信できます。次にdoPost()メソッドを作成し、POSTで送信された応答を取得し、ユーザー情報をDerbyデータベースに保存します。
Derbyに新しいユーザー・データを保存する
フォームを表示するサーブレットはすでに設定しました。しかし、サーブレットにdoPost()メソッドを実装し、POSTで送信されたデータを取得する必要があります。このメソッドを使うと、送信された変数の値を取得し、新しいレコードとしてデータベースに入れることができます。
送信されたデータを取得し、Derbyに保存する
サーブレットが現在の状態でユーザーが情報を送信すると、ブラウザにHTTP ERROR: 405が表示されます。これは、現状ではサーブレットでPOSTメソッドをサポートしていないためです。サーブレットにdoPost()メソッドを実装すると、この問題を解決できます。リスト4に示すようにRegisterServlet.javaファイルの定義を続けます。
リスト4.Javaサーブレットの続き
...
"</form></body></html>");
out.close();
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setBufferSize(8192);
PrintWriter out = response.getWriter();
out.println("<html>" +
"<head><title>Register</title></head>" +
"<body>" +
"<h1>Register</h1>\n");
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
boolean result = false;
if ((username != null) && (username.length() > 0)) {
... |
応答はdoGet()メソッドの場合と同じように設定されます。次に、HTML応答の先頭をブラウザに出力します。その後、送信された3つの値をPOST request変数からString型の変数に取得します。次に、ユーザー名が入力されNULLでないことを確認します。これで、データベースに挿入する必要があるデータを取得しました。リスト5に示すように、doPost()メソッドの定義を続けます。
リスト5.doPost()メソッドの続き
...
boolean result = false;
if ((username != null) && (username.length() > 0)) {
Driver driver = null;
try {
driver = (Driver)
(com.ibm.db2.jcc.DB2Driver.class).newInstance();
} catch(Exception e) {
throw new IllegalArgumentException("Unable to load, " +
"instantiate, or register driver " + driver +
": "+e.getMessage());
}
try {
Properties prop = new Properties();
prop.put("user", "system");
prop.put("password", "manager");
Connection conn = driver.
connect("jdbc:derby:net://localhost:1527/SystemDatabase;",
prop);
String sql = "insert into app.users values (?,?,?)";
PreparedStatement statement =
conn.prepareStatement(sql);
statement.setString(1, username);
statement.setString(2, email);
statement.setString(3, password);
statement.execute();
sql = "insert into app.groups_users values " +
"(?,'registeredUsers')";
statement = conn.prepareStatement(sql);
statement.setString(1, username);
statement.execute();
result = true;
... |
すべて予定どおりに進んだ場合、すべての値が正しくデータベースに送信され、例外が発生しなければ、result変数はtrueになります。使用するドライバはcom.ibm.db2.jcc.DB2Driverです。このシリーズの第1回で作成したmy-db-plan.xmlファイルで使われるドライバと同じものです。しかし、Geronimoでデプロイする前にこのコードをコンパイルする必要があるため、第1回でダウンロードしたファイルdb2jcc.jarとdb2jcc_license_c.jarがCLASSPATHにあることを確認してください。
2番目のtryステートメントでは、初めにPropertiesデータ構造を設定しています。これは、Geronimoに組み込みのDerbyデータベースSystemDatabaseに接続するときに必要となります。接続URL、ユーザー名、およびパスワードも第1回でmy-db-plan.xmlファイルで入力したものと同じです。次に、2つのSQLステートメントを設定して実行します。このSQLステートメントでは、新しいユーザー・データが入った新しいレコードをusersテーブルに挿入し、新しいレコードをgroups_usersテーブルに挿入して、registeredUsersグループに新しいユーザーを追加します。第1回で、ユーザー・エリアへのアクセスを許可するregistered-usersロールをgeronimo-web.xmlファイルのregisteredUsersグループにマップしたことを思い出してください。
次に、SQLステートメントに問題がある場合に備えて例外を処理し、登録の成功を確認するメッセージを表示し、POST応答を閉じます(リスト6を参照)。
リスト6.doPost()メソッドを終了する
...
statement.execute();
result = true;
} catch(Throwable e) {
result = false;
e.printStackTrace();
System.out.println(e.getMessage());
System.out.println("Error executing query");
out.println("Error in SQL!<br>");
}
}
if(result)
out.println("Thank you for registering!<br>" +
"Users login " +
"<a href='../users/'>here</a>.<br>\n" +
"Administrators login " +
"<a href='../admin/'>here</a>.<br>\n" +
"Back to the " +
"<a href='../'>main page</a>.<br>\n");
else
out.println("Invalid, try again!<br>" + form);
out.println("</form></body></html>");
out.close();
} |
2番目のtryステートメント中に例外が発生したら、result変数がfalseに設定されることに注意してください。この場合、ユーザー登録に問題があるか、サーブレットにデバッグが必要であることを示す応答がブラウザに送られます。例外が発生しなければ、ユーザーに登録を感謝するメッセージとログインへのリンクがユーザーに表示されます。最後に、out.close()ステートメントで応答を閉じ、doPost()メソッドが終了します。
以上で、新しいユーザー登録を受け付け、データをGeronimoに組み込みのDerbyデータベースに挿入するサーブレットの説明を終わります。
サーブレットを登録する
最後に、サーブレットの存在と配置先のページ位置をGeronimoに知らせるため、サーブレットを登録します。リスト7で示すように第1回のweb.xmlを編集します。
リスト7.サーブレットを登録する
...
version="2.4">
<servlet>
<display-name>RegisterServlet</display-name>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>servlets.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/login/register.html</url-pattern>
</servlet-mapping>
<security-role>
... |
ファイルに新しく追加する部分は太字で表しています。作成したサーブレットはservletsクラスにあるため、<servlet-class>タグでクラス名servlets.RegisterServletを指定します。次に、サーブレットをgeronimo-web.xmlファイルの<context-root>タグで指定された、アプリケーションのルート・ディレクトリーから始まるサーバーのディレクトリーにマップする必要があります。上記の設定では、サーブレットは次の場所で表示されます。
http://localhost:8080/sqlSecurityDemo/login/register.html
では、お楽しみの部分に移りましょう。Geronimoでこのアプリケーションをテストします。
アプリケーションをテストする
アプリケーションは実際に使う前に十分にテストすることが重要です。アプリケーションをビルドし、Geronimoに再デプロイした後、新しいサーブレットを登録しユーザー・エリアにログインするテストを行いましょう。
ビルドと再デプロイ
ここでは、アプリケーションをビルドし、アプリケーションの.warファイルを作成する必要があります。「ant」と入力し、Antを使って.warファイルをビルドします。
最後のsecurity.warファイルを作成し、Geronimoへの再デプロイの準備ができました。第1回で、すでにアプリケーションのセキュリティー・デプロイメント・プラン(my-db-plan.xml)とアプリケーション(security.war)はGeronimoにデプロイしました。ですから、今回は更新されたsecurity.warファイルだけを再デプロイします。次のように入力して再デプロイしてください。
java -jar bin/deployer.jar --user system --password manager redeploy security.war com/ibm/geronimo/security/myDbApp
第1回でデプロイした、現在デプロイされているモジュールが停止、アンロード、アンインストールされ、新しいモジュールが開始されます。次のように出力されます。
リスト8.最後のアプリケーションを再デプロイする
Stopped com/ibm/geronimo/security/myDbApp
Unloaded com/ibm/geronimo/security/myDbApp
Uninstalled com/ibm/geronimo/security/myDbApp
Deployed com/ibm/geronimo/security/myDbApp
Started com/ibm/geronimo/security/myDbApp
Redeployed com/ibm/geronimo/security/myDbApp
|
最後のアプリケーションがGeronimoにインストールされました。次に、その機能をテストします。
最終的なアプリケーションをテストする
新しいユーザーを登録してサーブレットをテストする必要があります。new users register hereリンクをクリックし、新しいユーザーを登録します。図2に示すように、ユーザー名としてnewuser、パスワードとしてnewpassを入力します。
図2. 新しいユーザーを登録する
[Submit]をクリックします。これで、新しいユーザーはデータベースに追加され、registeredUsersグループに追加されたはずです。Users login hereリンクをクリックしてユーザー・エリアにログインし、確認しましょう。図3に示すように、登録に使ったユーザー名とパスワードを使ってログインします。
図 3. newuserとしてログインする
ブラウザにユーザー・エリアが表示されれば、アプリケーションは動作しています。
まとめ
ここでは、Geronimoアプリケーション・サーバーを使ったレジストリー・システムを作成し、このシリーズの第1回で作成したデータベース・ログイン・システムの拡張に成功しました。コンテンツを動的に作成する簡単JSPスクリプト、およびユーザー登録データを取得し新しいユーザー・データをGeronimoに組み込みのDerbyデータベースに挿入する本格的なJavaサーブレットを作成する方法を学びました。
ダウンロード
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Tyler Andersonは2004年にBrigham Young Universityにてコンピューター・サイエンスの学位を取得しており、現在はコンピューター・エンジニアリングの修士取得に向けての最終学期を送っています。これまで、DPMG.COMのデータベース・プログラマーとして働いたことがあり、現在はオレゴン州BeavertonにあるStexar Corp.のエンジニアです。 |
記事の評価
|